From: Anthony Liguori <aliguori-NZpS4cJIG2HvQtjrzfazuQ@public.gmane.org>
To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Subject: [PATCH 7/7] Allow KVM from a normal QEMU binary
Date: Fri, 03 Nov 2006 00:35:15 -0600 [thread overview]
Message-ID: <454AE323.8090309@cs.utexas.edu> (raw)
In-Reply-To: <454AE007.5070905-NZpS4cJIG2HvQtjrzfazuQ@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 615 bytes --]
This patch depends on patch 6 and modifies the KVM changes to be an
"accelerator" for QEMU in much the same way kqemu is.
The basic idea was to introduce a use_kvm flag in CPUState and, where
appropriate, check for use_kvm before doing KVM specific things. There
are a number of places where a valid CPUState is not available or simply
not created yet. In these cases, we use the global kvm_allowed variable.
This isn't a very pretty approach but it seems to work. Figuring out
how to make this all work with SMP is going to largely depend on how SMP
gets implemented in KVM.
Regards,
Anthony Liguori
[-- Attachment #2: kvm-same-binary.diff --]
[-- Type: text/x-patch, Size: 15353 bytes --]
diff -r 29c67b2ba36e cpu-exec.c
--- a/cpu-exec.c Thu Nov 02 21:11:52 2006 -0600
+++ b/cpu-exec.c Thu Nov 02 21:11:52 2006 -0600
@@ -454,8 +454,10 @@ int cpu_exec(CPUState *env1)
#endif
#ifdef USE_KVM
- kvm_cpu_exec(env);
- longjmp(env->jmp_env, 1);
+ if (env->use_kvm) {
+ kvm_cpu_exec(env);
+ longjmp(env->jmp_env, 1);
+ }
#endif
T0 = 0; /* force lookup of first TB */
for(;;) {
diff -r 29c67b2ba36e exec.c
--- a/exec.c Thu Nov 02 21:11:52 2006 -0600
+++ b/exec.c Thu Nov 02 21:11:52 2006 -0600
@@ -1045,7 +1045,8 @@ int cpu_breakpoint_insert(CPUState *env,
env->breakpoints[env->nb_breakpoints++] = pc;
#ifdef USE_KVM
- kvm_update_debugger(env);
+ if (env->use_kvm)
+ kvm_update_debugger(env);
#endif
breakpoint_invalidate(env, pc);
@@ -1071,7 +1072,8 @@ int cpu_breakpoint_remove(CPUState *env,
env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
#ifdef USE_KVM
- kvm_update_debugger(env);
+ if (env->use_kvm)
+ kvm_update_debugger(env);
#endif
breakpoint_invalidate(env, pc);
@@ -1093,7 +1095,8 @@ void cpu_single_step(CPUState *env, int
tb_flush(env);
}
#ifdef USE_KVM
- kvm_update_debugger(env);
+ if (env->use_kvm)
+ kvm_update_debugger(env);
#endif
#endif
}
diff -r 29c67b2ba36e hw/cirrus_vga.c
--- a/hw/cirrus_vga.c Thu Nov 02 21:11:52 2006 -0600
+++ b/hw/cirrus_vga.c Thu Nov 02 21:11:52 2006 -0600
@@ -2596,7 +2596,9 @@ static void cirrus_update_memory_access(
mode = s->gr[0x05] & 0x7;
if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
#ifdef USE_KVM
- if (s->cirrus_lfb_addr && s->cirrus_lfb_end && !s->map_addr) {
+ CPUState *env = cpu_single_env; /* XXX: SMP support */
+ if (env->use_kvm && s->cirrus_lfb_addr && s->cirrus_lfb_end &&
+ !s->map_addr) {
void *vram_pointer, *old_vram;
vram_pointer = set_vram_mapping(s->cirrus_lfb_addr,
@@ -2616,9 +2618,14 @@ static void cirrus_update_memory_access(
s->cirrus_linear_write[1] = cirrus_linear_mem_writew;
s->cirrus_linear_write[2] = cirrus_linear_mem_writel;
} else {
+#ifdef USE_KVM
+ CPUState *env;
+#endif
generic_io:
#ifdef USE_KVM
- if (s->cirrus_lfb_addr && s->cirrus_lfb_end && s->map_addr) {
+ env = cpu_single_env;
+ if (env->use_kvm && s->cirrus_lfb_addr && s->cirrus_lfb_end &&
+ s->map_addr) {
int error;
void *old_vram = NULL;
@@ -2993,6 +3000,9 @@ static void cirrus_vga_save(QEMUFile *f,
static void cirrus_vga_save(QEMUFile *f, void *opaque)
{
CirrusVGAState *s = opaque;
+#ifdef USE_KVM
+ CPUState *env = cpu_single_env;
+#endif
qemu_put_be32s(f, &s->latch);
qemu_put_8s(f, &s->sr_index);
@@ -3029,14 +3039,19 @@ static void cirrus_vga_save(QEMUFile *f,
the state when the blitter is active */
#ifdef USE_KVM
- qemu_put_be32s(f, &s->real_vram_size);
- qemu_put_buffer(f, s->vram_ptr, s->real_vram_size);
+ if (env->use_kvm) { /* XXX: KVM images ought to be loadable in QEMU */
+ qemu_put_be32s(f, &s->real_vram_size);
+ qemu_put_buffer(f, s->vram_ptr, s->real_vram_size);
+ }
#endif
}
static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id)
{
CirrusVGAState *s = opaque;
+#ifdef USE_KVM
+ CPUState *env = cpu_single_env;
+#endif
if (version_id != 1)
return -EINVAL;
@@ -3076,7 +3091,7 @@ static int cirrus_vga_load(QEMUFile *f,
qemu_get_be32s(f, &s->hw_cursor_y);
#ifdef USE_KVM
- {
+ if (env->use_kvm) {
int real_vram_size;
qemu_get_be32s(f, &real_vram_size);
if (real_vram_size != s->real_vram_size) {
@@ -3247,12 +3262,14 @@ static void cirrus_pci_lfb_map(PCIDevice
cpu_register_physical_memory(addr, s->vram_size,
s->cirrus_linear_io_addr);
#ifdef USE_KVM
- s->cirrus_lfb_addr = addr;
- s->cirrus_lfb_end = addr + VGA_RAM_SIZE;
-
- if (s->map_addr && (s->cirrus_lfb_addr != s->map_addr) &&
- (s->cirrus_lfb_end != s->map_end))
- printf("cirrus vga map change while on lfb mode\n");
+ if (kqemu_allowed) {
+ s->cirrus_lfb_addr = addr;
+ s->cirrus_lfb_end = addr + VGA_RAM_SIZE;
+
+ if (s->map_addr && (s->cirrus_lfb_addr != s->map_addr) &&
+ (s->cirrus_lfb_end != s->map_end))
+ printf("cirrus vga map change while on lfb mode\n");
+ }
#endif
cpu_register_physical_memory(addr + 0x1000000, 0x400000,
diff -r 29c67b2ba36e hw/pc.c
--- a/hw/pc.c Thu Nov 02 21:11:52 2006 -0600
+++ b/hw/pc.c Thu Nov 02 21:11:52 2006 -0600
@@ -610,6 +610,7 @@ static void pc_init_ne2k_isa(NICInfo *nd
#ifdef USE_KVM
extern kvm_context_t kvm_context;
+extern int kvm_allowed;
#endif
/* PC hardware initialisation */
@@ -682,7 +683,9 @@ static void pc_init1(int ram_size, int v
cpu_register_physical_memory(0xc0000, 0x10000,
vga_bios_offset | IO_MEM_ROM);
#ifdef USE_KVM
- memcpy(phys_ram_base + 0xc0000, phys_ram_base + vga_bios_offset, 0x10000);
+ if (kvm_allowed)
+ memcpy(phys_ram_base + 0xc0000, phys_ram_base + vga_bios_offset,
+ 0x10000);
#endif
/* map the last 128KB of the BIOS in ISA space */
@@ -695,21 +698,25 @@ static void pc_init1(int ram_size, int v
isa_bios_size,
(bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
#ifdef USE_KVM
- memcpy(phys_ram_base + 0x100000 - isa_bios_size, phys_ram_base + (bios_offset + bios_size - isa_bios_size), isa_bios_size);
+ if (kvm_allowed)
+ memcpy(phys_ram_base + 0x100000 - isa_bios_size,
+ phys_ram_base + (bios_offset + bios_size - isa_bios_size),
+ isa_bios_size);
#endif
/* map all the bios at the top of memory */
cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
#ifdef USE_KVM
- bios_mem = kvm_create_phys_mem(kvm_context, (uint32_t)(-bios_size),
- bios_size, 2, 0, 1);
- if (!bios_mem) {
- exit(1);
- }
- memcpy(bios_mem, phys_ram_base + bios_offset, bios_size);
-
- cpu_register_physical_memory(phys_ram_size - KVM_EXTRA_PAGES * 4096, KVM_EXTRA_PAGES * 4096,
- (phys_ram_size - KVM_EXTRA_PAGES * 4096) | IO_MEM_ROM);
+ if (kvm_allowed) {
+ bios_mem = kvm_create_phys_mem(kvm_context, (uint32_t)(-bios_size),
+ bios_size, 2, 0, 1);
+ if (!bios_mem)
+ exit(1);
+ memcpy(bios_mem, phys_ram_base + bios_offset, bios_size);
+
+ cpu_register_physical_memory(phys_ram_size - KVM_EXTRA_PAGES * 4096, KVM_EXTRA_PAGES * 4096,
+ (phys_ram_size - KVM_EXTRA_PAGES * 4096) | IO_MEM_ROM);
+ }
#endif
diff -r 29c67b2ba36e hw/vga.c
--- a/hw/vga.c Thu Nov 02 21:11:52 2006 -0600
+++ b/hw/vga.c Thu Nov 02 21:12:55 2006 -0600
@@ -1375,6 +1375,10 @@ static int bitmap_get_dirty(unsigned lon
#endif
+#ifdef USE_KVM
+extern int kvm_allowed;
+#endif
+
/*
* graphic modes
*/
@@ -1393,11 +1397,8 @@ static void vga_draw_graphic(VGAState *s
#define BITMAP_SIZE ((8*1024*1024) / 4096 / 8 / sizeof(long))
unsigned long bitmap[BITMAP_SIZE];
- kvm_get_dirty_pages(kvm_context, 1, &bitmap);
-
-#define cpu_physical_memory_get_dirty(addr, type) \
- (bitmap_get_dirty(bitmap, (addr - s->vram_offset) >> TARGET_PAGE_BITS) \
- | cpu_physical_memory_get_dirty(addr, type))
+ if (kvm_allowed)
+ kvm_get_dirty_pages(kvm_context, 1, &bitmap);
#endif
full_update |= update_basic_params(s);
@@ -1506,10 +1507,16 @@ static void vga_draw_graphic(VGAState *s
update = full_update |
cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
+ if (kvm_allowed) {
+ update |= bitmap_get_dirty(bitmap, (page0 - s->vram_offset) >> TARGET_PAGE_BITS);
+ update |= bitmap_get_dirty(bitmap, (page1 - s->vram_offset) >> TARGET_PAGE_BITS);
+ }
if ((page1 - page0) > TARGET_PAGE_SIZE) {
/* if wide line, can use another page */
update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
VGA_DIRTY_FLAG);
+ if (kvm_allowed)
+ update |= bitmap_get_dirty(bitmap, (page0 - s->vram_offset) >> TARGET_PAGE_BITS);
}
/* explicit invalidation for the hardware cursor */
update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
@@ -1751,6 +1758,10 @@ static void vga_map(PCIDevice *pci_dev,
}
}
+#ifdef USE_KVM
+extern int kvm_allowed;
+#endif
+
/* when used on xen/kvm environment, the vga_ram_base is not used */
void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
unsigned long vga_ram_offset, int vga_ram_size)
@@ -1785,7 +1796,10 @@ void vga_common_init(VGAState *s, Displa
#ifndef USE_KVM
s->vram_ptr = vga_ram_base;
#else
- s->vram_ptr = qemu_malloc(vga_ram_size);
+ if (kvm_allowed)
+ s->vram_ptr = qemu_malloc(vga_ram_size);
+ else
+ s->vram_ptr = vga_ram_base;
#endif
s->vram_offset = vga_ram_offset;
s->vram_size = vga_ram_size;
diff -r 29c67b2ba36e target-i386/cpu.h
--- a/target-i386/cpu.h Thu Nov 02 21:11:52 2006 -0600
+++ b/target-i386/cpu.h Thu Nov 02 21:11:52 2006 -0600
@@ -532,6 +532,7 @@ typedef struct CPUX86State {
#ifdef USE_KVM
int kvm_pending_int;
+ int use_kvm;
#endif
/* in order to simplify APIC support, we leave this pointer to the
diff -r 29c67b2ba36e target-i386/helper.c
--- a/target-i386/helper.c Thu Nov 02 21:11:52 2006 -0600
+++ b/target-i386/helper.c Thu Nov 02 21:11:52 2006 -0600
@@ -189,7 +189,7 @@ static inline void get_ss_esp_from_tss(u
* Bit 1 is the Busy bit. We believe it is legal to interrupt into a busy
* segment
*/
- if ((type & 5) != 1)
+ if ((env->use_kvm && (type & 5) != 1) || (type & 7) != 1)
#else
if ((type & 7) != 1)
#endif
@@ -838,8 +838,10 @@ static void do_interrupt64(int intno, in
target_ulong old_eip, esp, offset;
#ifdef USE_KVM
- printf("%s: unexpect\n", __FUNCTION__);
- exit(-1);
+ if (env->use_kvm) {
+ printf("%s: unexpect\n", __FUNCTION__);
+ exit(-1);
+ }
#endif
has_error_code = 0;
@@ -1126,8 +1128,10 @@ void do_interrupt_user(int intno, int is
uint32_t e2;
#ifdef USE_KVM
- printf("%s: unexpect\n", __FUNCTION__);
- exit(-1);
+ if (env->use_kvm) {
+ printf("%s: unexpect\n", __FUNCTION__);
+ exit(-1);
+ }
#endif
dt = &env->idt;
ptr = dt->base + (intno * 8);
@@ -1155,8 +1159,10 @@ void do_interrupt(int intno, int is_int,
target_ulong next_eip, int is_hw)
{
#ifdef USE_KVM
- printf("%s: unexpect\n", __FUNCTION__);
- exit(-1);
+ if (env->use_kvm) {
+ printf("%s: unexpect\n", __FUNCTION__);
+ exit(-1);
+ }
#endif
if (loglevel & CPU_LOG_INT) {
if ((env->cr[0] & CR0_PE_MASK)) {
@@ -1687,7 +1693,7 @@ void helper_ljmp_protected_T0_T1(int nex
get_seg_base(e1, e2), limit, e2);
EIP = new_eip;
#ifdef USE_KVM
- if (e2 & DESC_L_MASK) {
+ if (env->use_kvm && (e2 & DESC_L_MASK)) {
env->exception_index = -1;
cpu_loop_exit();
}
diff -r 29c67b2ba36e target-i386/helper2.c
--- a/target-i386/helper2.c Thu Nov 02 21:11:52 2006 -0600
+++ b/target-i386/helper2.c Thu Nov 02 21:11:52 2006 -0600
@@ -140,6 +140,12 @@ CPUX86State *cpu_x86_init(void)
cpu_reset(env);
#ifdef USE_KQEMU
kqemu_init(env);
+#endif
+#ifdef USE_KVM
+ {
+ extern int kvm_allowed;
+ env->use_kvm = kvm_allowed;
+ }
#endif
return env;
}
diff -r 29c67b2ba36e vl.c
--- a/vl.c Thu Nov 02 21:11:52 2006 -0600
+++ b/vl.c Thu Nov 02 21:11:52 2006 -0600
@@ -4594,7 +4594,8 @@ int cpu_load(QEMUFile *f, void *opaque,
env->hflags = hflags;
tlb_flush(env, 1);
#ifdef USE_KVM
- kvm_load_registers(env);
+ if (env->use_kvm)
+ kvm_load_registers(env);
#endif
return 0;
}
@@ -4761,7 +4762,7 @@ static void ram_save(QEMUFile *f, void *
qemu_put_be32(f, phys_ram_size);
for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) {
#ifdef USE_KVM
- if ((i>=0xa0000) && (i<0xc0000)) /* do not access video-addresses */
+ if (kvm_allowed && (i>=0xa0000) && (i<0xc0000)) /* do not access video-addresses */
continue;
#endif
ram_put_page(f, phys_ram_base + i, TARGET_PAGE_SIZE);
@@ -4771,14 +4772,13 @@ static int ram_load(QEMUFile *f, void *o
static int ram_load(QEMUFile *f, void *opaque, int version_id)
{
int i, ret;
-
if (version_id != 1)
return -EINVAL;
if (qemu_get_be32(f) != phys_ram_size)
return -EINVAL;
for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) {
#ifdef USE_KVM
- if ((i>=0xa0000) && (i<0xc0000)) /* do not access video-addresses */
+ if (kqemu_allowed && (i>=0xa0000) && (i<0xc0000)) /* do not access video-addresses */
continue;
#endif
ret = ram_get_page(f, phys_ram_base + i, TARGET_PAGE_SIZE);
@@ -5230,6 +5230,9 @@ void help(void)
#ifdef USE_KQEMU
"-kernel-kqemu enable KQEMU full virtualization (default is user mode only)\n"
"-no-kqemu disable KQEMU kernel module usage\n"
+#endif
+#ifdef USE_KVM
+ "-enable-kvm enable KVM full virtualization\n"
#endif
#ifdef USE_CODE_COPY
"-no-code-copy disable code copy acceleration\n"
@@ -5319,6 +5322,7 @@ enum {
QEMU_OPTION_smp,
QEMU_OPTION_vnc,
QEMU_OPTION_no_acpi,
+ QEMU_OPTION_enable_kvm,
};
typedef struct QEMUOption {
@@ -5374,6 +5378,9 @@ const QEMUOption qemu_options[] = {
#ifdef USE_KQEMU
{ "no-kqemu", 0, QEMU_OPTION_no_kqemu },
{ "kernel-kqemu", 0, QEMU_OPTION_kernel_kqemu },
+#endif
+#ifdef USE_KVM
+ { "enable-kvm", 0, QEMU_OPTION_enable_kvm },
#endif
#if defined(TARGET_PPC) || defined(TARGET_SPARC)
{ "g", 1, QEMU_OPTION_g },
@@ -6007,6 +6014,11 @@ int main(int argc, char **argv)
kqemu_allowed = 2;
break;
#endif
+#ifdef USE_KVM
+ case QEMU_OPTION_enable_kvm:
+ kvm_allowed = 1;
+ break;
+#endif
case QEMU_OPTION_usb:
usb_enabled = 1;
break;
@@ -6088,8 +6100,17 @@ int main(int argc, char **argv)
/* init the memory */
#if USE_KVM
- phys_ram_size = ram_size + vga_ram_size + bios_size + KVM_EXTRA_PAGES * 4096;
- kvm_qemu_init();
+ phys_ram_size = ram_size + vga_ram_size + bios_size;
+ if (kvm_allowed) {
+ phys_ram_size += KVM_EXTRA_PAGES * 4096;
+ kvm_qemu_init();
+ } else {
+ phys_ram_base = qemu_vmalloc(phys_ram_size);
+ if (!phys_ram_base) {
+ fprintf(stderr, "Could not allocate physical memory\n");
+ exit(1);
+ }
+ }
#else
phys_ram_size = ram_size + vga_ram_size + bios_size;
phys_ram_base = qemu_vmalloc(phys_ram_size);
diff -r 29c67b2ba36e vl.h
--- a/vl.h Thu Nov 02 21:11:52 2006 -0600
+++ b/vl.h Thu Nov 02 21:11:52 2006 -0600
@@ -148,6 +148,7 @@ extern int graphic_depth;
extern int graphic_depth;
extern const char *keyboard_layout;
extern int kqemu_allowed;
+extern int kvm_allowed;
extern int win2k_install_hack;
extern int usb_enabled;
extern int smp_cpus;
[-- Attachment #3: Type: text/plain, Size: 373 bytes --]
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
[-- Attachment #4: Type: text/plain, Size: 186 bytes --]
_______________________________________________
kvm-devel mailing list
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/kvm-devel
next prev parent reply other threads:[~2006-11-03 6:35 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-11-03 6:21 [PATCH 0/7] Split up QEMU patches Anthony Liguori
[not found] ` <454AE007.5070905-NZpS4cJIG2HvQtjrzfazuQ@public.gmane.org>
2006-11-03 6:25 ` [PATCH 1/7] Compile fix for usb-linux.c Anthony Liguori
2006-11-03 6:26 ` [PATCH 2/7] APIC save/restore fix Anthony Liguori
2006-11-03 6:27 ` [PATCH 3/7] Timer " Anthony Liguori
2006-11-03 6:29 ` [PATCH 4/7] gdbstub for x86-64 Anthony Liguori
2006-11-03 6:30 ` [PATCH 5/7] VMDK Snapshot Support Anthony Liguori
2006-11-03 6:31 ` [PATCH 6/7] KVM changes for QEMU Anthony Liguori
2006-11-03 6:35 ` Anthony Liguori [this message]
[not found] ` <454AE323.8090309-NZpS4cJIG2HvQtjrzfazuQ@public.gmane.org>
2006-11-05 9:27 ` [PATCH 7/7] Allow KVM from a normal QEMU binary Avi Kivity
[not found] ` <454DAE74.4030306-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2006-11-05 17:28 ` Anthony Liguori
[not found] ` <454E1F40.2070200-NZpS4cJIG2HvQtjrzfazuQ@public.gmane.org>
2006-11-05 17:48 ` Avi Kivity
[not found] ` <454E23EE.7040505-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2006-11-05 18:18 ` Anthony Liguori
[not found] ` <454E2ADC.1060607-NZpS4cJIG2HvQtjrzfazuQ@public.gmane.org>
2006-11-05 18:29 ` Avi Kivity
[not found] ` <454E2DA4.8070405-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2006-11-05 19:53 ` Anthony Liguori
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=454AE323.8090309@cs.utexas.edu \
--to=aliguori-nzps4cjig2hvqtjrzfazuq@public.gmane.org \
--cc=kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox