From patchwork Tue Dec 10 15:47:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nick Rosbrook X-Patchwork-Id: 11282899 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5CF0C14BD for ; Tue, 10 Dec 2019 15:50:32 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2DD87206D5 for ; Tue, 10 Dec 2019 15:50:32 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="YSOwNhHO" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2DD87206D5 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1iehl9-0003go-Ub; Tue, 10 Dec 2019 15:49:11 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1iehl8-0003fz-Td for xen-devel@lists.xenproject.org; Tue, 10 Dec 2019 15:49:10 +0000 X-Inumbo-ID: 775cd34c-1b64-11ea-a1e1-bc764e2007e4 Received: from mail-qk1-x732.google.com (unknown [2607:f8b0:4864:20::732]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 775cd34c-1b64-11ea-a1e1-bc764e2007e4; Tue, 10 Dec 2019 15:48:10 +0000 (UTC) Received: by mail-qk1-x732.google.com with SMTP id d202so16808753qkb.1 for ; Tue, 10 Dec 2019 07:48:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=6bFttf93Zv7bJw+HhrXFNoNF5zm0+Ns2KTF1xAY7wfU=; b=YSOwNhHOINHafwHrTozijvpCCUTZw4CF4f9Xde08G5lN/lT5x+t50BZoZ/JDp+97bV WdR/vz/OLl6sOrXlwjEXG0zZ88d2fyprVXDlLRNcmaW0yVlFu584yISzdme3/k/aKtmD JoBbjyCtXD5DzoOL+qdTxaanRUrxT9h6IPZUxRBc0FJCTHVmjAxL6N3CX57OjPOnvbto tNkLDMzYb9O8HZ5IIn1kOoxwyZ4/7Synz2jYoIViduXzvLU4BuCqq43vreVvr3BMC7Ci WBg0mQn1TH9G5QjxDPmybFrKHJ6hpO91OxaWvHKxULRApKPwPTY0Bf/4ksrYE6ET37Ay qNnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=6bFttf93Zv7bJw+HhrXFNoNF5zm0+Ns2KTF1xAY7wfU=; b=nycQ7TggWgq8xhqIFUR5JjPlI2aFJ9s0Dj02pwKtvp0PbXYFsYRxLJJ4Ls5xYtVv2S 6VGPRLv5B3wq9ttrffcXg3ukPgfaItbMuZ7eXPqNmvlrRm2U6GIQB7eth1GD3QHCmE6W O4CAUsUuTzT+hHOYtWTBVpnbujf5yhWSx2zOmiOiBPvE+0PqRsaA4xE1FVlLMDTj7G+N Jkfu30Km9cPSX/tJY8mGJljRQ4a6BhHAXyPycqK6hWFZTsFbh6Jt5py0gQ7pxP8FWI6E VOKwSBtBFFIb6IyDn5cdaaLwFiVtdlEHC4TFUK3IX0O4stOTb5PpPP6AjpguSM4rthFN 1LcQ== X-Gm-Message-State: APjAAAXQt4D8J2N9rPgO0WC8OTFauFgM+LoCfQaq7gVY8X2tVlOWGrhc Qb8ivsARdnxq3OPyR0JWQAc/am3P X-Google-Smtp-Source: APXvYqxgVOQgzkzyL9VxP4Yr1fHy7lSCRl5pj/wBz9R+kACeKCs39hebWZq2Rxh27veMx843VeBFtw== X-Received: by 2002:a37:e55:: with SMTP id 82mr33915836qko.370.1575992889007; Tue, 10 Dec 2019 07:48:09 -0800 (PST) Received: from five.crux.rad.ainfosec.com (209-217-208-226.northland.net. [209.217.208.226]) by smtp.googlemail.com with ESMTPSA id m29sm1247848qtf.1.2019.12.10.07.48.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Dec 2019 07:48:08 -0800 (PST) From: Nick Rosbrook To: xen-devel@lists.xenproject.org Date: Tue, 10 Dec 2019 10:47:31 -0500 Message-Id: <55d5a61e30b20df027a159834f18d777c8e6b0d9.1575990937.git.rosbrookn@ainfosec.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: References: MIME-Version: 1.0 Subject: [Xen-devel] [PATCH v3 16/22] golang/xenlight: implement keyed union C to Go marshaling X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Nick Rosbrook , Ian Jackson , kerriganb@ainfosec.com, George Dunlap , Wei Liu Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" From: Nick Rosbrook Switch over union key to determine how to populate 'union' in Go struct. Since the unions of C types cannot be directly accessed in cgo, use a typeof trick to typedef a struct in the cgo preamble that is analagous to each inner struct of a keyed union. For example, to define a struct for the hvm inner struct of libxl_domain_build_info, do: typedef typeof(((struct libxl_domain_build_info *)NULL)->u.hvm) libxl_domain_build_info_type_union_hvm; Signed-off-by: Nick Rosbrook Reviewed-by: George Dunlap --- Changes in v2: - Do not use global variable for extra helper function definitions. Instead, return a tuple which contains a list of extra helper functions associated with the original. Changes in v3: - Use the new xenlight_golang_convert_from_C function for field copying/ type conversion. - Use a typeof trick in the cgo preamble to define structs for the inner struct of keyed unions, instead of explicitly defining the fields. --- tools/golang/xenlight/gengotypes.py | 129 +++++++++- tools/golang/xenlight/helpers.gen.go | 346 +++++++++++++++++++++++++++ 2 files changed, 464 insertions(+), 11 deletions(-) diff --git a/tools/golang/xenlight/gengotypes.py b/tools/golang/xenlight/gengotypes.py index 1fe56179e2..b68c1aa66b 100644 --- a/tools/golang/xenlight/gengotypes.py +++ b/tools/golang/xenlight/gengotypes.py @@ -24,6 +24,10 @@ go_keywords = ['type', 'func'] go_builtin_types = ['bool', 'string', 'int', 'byte', 'uint16', 'uint32', 'uint64'] +# cgo preamble for xenlight_helpers.go, created during type generation and +# written later. +cgo_helpers_preamble = [] + def xenlight_golang_generate_types(path = None, types = None, comment = None): """ Generate a .go file (types.gen.go by default) @@ -124,7 +128,7 @@ def xenlight_golang_define_struct(ty = None, typename = None, nested = False): extras.extend(r[1]) elif isinstance(f.type, idl.KeyedUnion): - r = xenlight_golang_define_union(f.type, ty.typename) + r = xenlight_golang_define_union(f.type, ty.typename, f.name) s += r[0] extras.extend(r[1]) @@ -137,7 +141,7 @@ def xenlight_golang_define_struct(ty = None, typename = None, nested = False): return (s,extras) -def xenlight_golang_define_union(ty = None, structname = ''): +def xenlight_golang_define_union(ty = None, struct_name = '', union_name = ''): """ Generate the Go translation of a KeyedUnion. @@ -149,7 +153,7 @@ def xenlight_golang_define_union(ty = None, structname = ''): s = '' extras = [] - interface_name = '{}_{}_union'.format(structname, ty.keyvar.name) + interface_name = '{}_{}_union'.format(struct_name, ty.keyvar.name) interface_name = xenlight_golang_fmt_name(interface_name, exported=False) s += 'type {} interface {{\n'.format(interface_name) @@ -163,11 +167,18 @@ def xenlight_golang_define_union(ty = None, structname = ''): continue # Define struct - name = '{}_{}_union_{}'.format(structname, ty.keyvar.name, f.name) + name = '{}_{}_union_{}'.format(struct_name, ty.keyvar.name, f.name) r = xenlight_golang_define_struct(f.type, typename=name) extras.append(r[0]) extras.extend(r[1]) + # This typeof trick ensures that the fields used in the cgo struct + # used for marshaling are the same as the fields of the union in the + # actual C type, and avoids re-defining all of those fields. + s = 'typedef typeof(((struct {} *)NULL)->{}.{}){};' + s = s.format(struct_name, union_name, f.name, name) + cgo_helpers_preamble.append(s) + # Define function to implement 'union' interface name = xenlight_golang_fmt_name(name) s = 'func (x {}) is{}(){{}}\n'.format(name, interface_name) @@ -195,6 +206,7 @@ def xenlight_golang_generate_helpers(path = None, types = None, comment = None): if comment is not None: f.write(comment) f.write('package xenlight\n') + f.write('import (\n"unsafe"\n"errors"\n"fmt"\n)\n') # Cgo preamble f.write('/*\n') @@ -203,15 +215,25 @@ def xenlight_golang_generate_helpers(path = None, types = None, comment = None): f.write('#include \n') f.write('\n') + for s in cgo_helpers_preamble: + f.write(s) + f.write('\n') + f.write('*/\nimport "C"\n') for ty in types: if not isinstance(ty, idl.Struct): continue - f.write(xenlight_golang_define_from_C(ty)) + (fdef, extras) = xenlight_golang_define_from_C(ty) + + f.write(fdef) f.write('\n') + for extra in extras: + f.write(extra) + f.write('\n') + go_fmt(path) def xenlight_golang_define_from_C(ty = None): @@ -225,6 +247,7 @@ def xenlight_golang_define_from_C(ty = None): cname = ty.typename body = '' + extras = [] for f in ty.fields: if f.type.typename is not None: @@ -240,14 +263,17 @@ def xenlight_golang_define_from_C(ty = None): body += xenlight_golang_convert_from_C(nf,outer_name=f.name) elif isinstance(f.type, idl.KeyedUnion): - pass + r = xenlight_golang_union_from_C(f.type, f.name, ty.typename) + + body += r[0] + extras.extend(r[1]) else: raise Exception('type {} not supported'.format(f.type)) - return func.format(goname, cname, body) + return (func.format(goname, cname, body), extras) -def xenlight_golang_convert_from_C(ty = None, outer_name = None): +def xenlight_golang_convert_from_C(ty = None, outer_name = None, cvarname = None): """ Returns a line of Go code that converts the C type represented by ty to its corresponding Go type. @@ -257,6 +283,10 @@ def xenlight_golang_convert_from_C(ty = None, outer_name = None): """ s = '' + # Use 'xc' as the name for the C variable unless otherwise specified + if cvarname is None: + cvarname = 'xc' + gotypename = xenlight_golang_fmt_name(ty.type.typename) goname = xenlight_golang_fmt_name(ty.name) cname = ty.name @@ -280,18 +310,95 @@ def xenlight_golang_convert_from_C(ty = None, outer_name = None): if not is_castable: # If the type is not castable, we need to call its fromC # function. - s += 'if err := x.{}.fromC(&xc.{});'.format(goname,cname) + s += 'if err := x.{}.fromC(&{}.{});'.format(goname,cvarname,cname) s += 'err != nil {\n return err \n}\n' elif gotypename == 'string': # Use the cgo helper for converting C strings. - s += 'x.{} = C.GoString(xc.{})\n'.format(goname, cname) + s += 'x.{} = C.GoString({}.{})\n'.format(goname,cvarname,cname) else: - s += 'x.{} = {}(xc.{})\n'.format(goname, gotypename, cname) + s += 'x.{} = {}({}.{})\n'.format(goname,gotypename,cvarname,cname) return s +def xenlight_golang_union_from_C(ty = None, union_name = '', struct_name = ''): + extras = [] + + keyname = ty.keyvar.name + gokeyname = xenlight_golang_fmt_name(keyname) + keytype = ty.keyvar.type.typename + gokeytype = xenlight_golang_fmt_name(keytype) + + interface_name = '{}_{}_union'.format(struct_name, keyname) + interface_name = xenlight_golang_fmt_name(interface_name, exported=False) + + cgo_keyname = keyname + if cgo_keyname in go_keywords: + cgo_keyname = '_' + cgo_keyname + + cases = {} + + for f in ty.fields: + val = '{}_{}'.format(keytype, f.name) + val = xenlight_golang_fmt_name(val) + + # Add to list of cases to make for the switch + # statement below. + if f.type is None: + continue + + cases[f.name] = val + + # Define fromC func for 'union' struct. + typename = '{}_{}_union_{}'.format(struct_name,keyname,f.name) + gotypename = xenlight_golang_fmt_name(typename) + + # Define the function here. The cases for keyed unions are a little + # different. + s = 'func (x *{}) fromC(xc *C.{}) error {{\n'.format(gotypename,struct_name) + s += 'if {}(xc.{}) != {} {{\n'.format(gokeytype,cgo_keyname,val) + err_string = '"expected union key {}"'.format(val) + s += 'return errors.New({})\n'.format(err_string) + s += '}\n\n' + s += 'tmp := (*C.{})(unsafe.Pointer(&xc.{}[0]))\n'.format(typename,union_name) + + for nf in f.type.fields: + s += xenlight_golang_convert_from_C(nf,cvarname='tmp') + + s += 'return nil\n' + s += '}\n' + + extras.append(s) + + s = 'x.{} = {}(xc.{})\n'.format(gokeyname,gokeytype,cgo_keyname) + s += 'switch x.{}{{\n'.format(gokeyname) + + # Create switch statement to determine which 'union element' + # to populate in the Go struct. + for case_name, case_val in cases.items(): + s += 'case {}:\n'.format(case_val) + + gotype = '{}_{}_union_{}'.format(struct_name,keyname,case_name) + gotype = xenlight_golang_fmt_name(gotype) + goname = '{}_{}'.format(keyname,case_name) + goname = xenlight_golang_fmt_name(goname,exported=False) + + s += 'var {} {}\n'.format(goname, gotype) + s += 'if err := {}.fromC(xc);'.format(goname) + s += 'err != nil {\n return err \n}\n' + + field_name = xenlight_golang_fmt_name('{}_union'.format(keyname)) + s += 'x.{} = {}\n'.format(field_name, goname) + + # End switch statement + s += 'default:\n' + err_string = '"invalid union key \'%v\'", x.{}'.format(gokeyname) + s += 'return fmt.Errorf({})'.format(err_string) + s += '}\n' + + return (s,extras) + def xenlight_golang_fmt_name(name, exported = True): """ Take a given type name and return an diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go index 576aebcf6d..e6eee234c0 100644 --- a/tools/golang/xenlight/helpers.gen.go +++ b/tools/golang/xenlight/helpers.gen.go @@ -5,11 +5,28 @@ // package xenlight +import ( + "errors" + "fmt" + "unsafe" +) + /* #cgo LDFLAGS: -lxenlight #include #include +typedef typeof(((struct libxl_channelinfo *)NULL)->u.pty)libxl_channelinfo_connection_union_pty; +typedef typeof(((struct libxl_domain_build_info *)NULL)->u.hvm)libxl_domain_build_info_type_union_hvm; +typedef typeof(((struct libxl_domain_build_info *)NULL)->u.pv)libxl_domain_build_info_type_union_pv; +typedef typeof(((struct libxl_domain_build_info *)NULL)->u.pvh)libxl_domain_build_info_type_union_pvh; +typedef typeof(((struct libxl_device_usbdev *)NULL)->u.hostdev)libxl_device_usbdev_type_union_hostdev; +typedef typeof(((struct libxl_device_channel *)NULL)->u.socket)libxl_device_channel_connection_union_socket; +typedef typeof(((struct libxl_event *)NULL)->u.domain_shutdown)libxl_event_type_union_domain_shutdown; +typedef typeof(((struct libxl_event *)NULL)->u.disk_eject)libxl_event_type_union_disk_eject; +typedef typeof(((struct libxl_event *)NULL)->u.operation_complete)libxl_event_type_union_operation_complete; +typedef typeof(((struct libxl_psr_hw_info *)NULL)->u.cat)libxl_psr_hw_info_type_union_cat; +typedef typeof(((struct libxl_psr_hw_info *)NULL)->u.mba)libxl_psr_hw_info_type_union_mba; */ import "C" @@ -137,7 +154,28 @@ func (x *Channelinfo) fromC(xc *C.libxl_channelinfo) error { x.State = int(xc.state) x.Evtch = int(xc.evtch) x.Rref = int(xc.rref) + x.Connection = ChannelConnection(xc.connection) + switch x.Connection { + case ChannelConnectionPty: + var connectionPty ChannelinfoConnectionUnionPty + if err := connectionPty.fromC(xc); err != nil { + return err + } + x.ConnectionUnion = connectionPty + default: + return fmt.Errorf("invalid union key '%v'", x.Connection) + } + + return nil +} + +func (x *ChannelinfoConnectionUnionPty) fromC(xc *C.libxl_channelinfo) error { + if ChannelConnection(xc.connection) != ChannelConnectionPty { + return errors.New("expected union key ChannelConnectionPty") + } + tmp := (*C.libxl_channelinfo_connection_union_pty)(unsafe.Pointer(&xc.u[0])) + x.Path = C.GoString(tmp.path) return nil } @@ -340,6 +378,29 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error { return err } x.Tee = TeeType(xc.tee) + x.Type = DomainType(xc._type) + switch x.Type { + case DomainTypePv: + var typePv DomainBuildInfoTypeUnionPv + if err := typePv.fromC(xc); err != nil { + return err + } + x.TypeUnion = typePv + case DomainTypeHvm: + var typeHvm DomainBuildInfoTypeUnionHvm + if err := typeHvm.fromC(xc); err != nil { + return err + } + x.TypeUnion = typeHvm + case DomainTypePvh: + var typePvh DomainBuildInfoTypeUnionPvh + if err := typePvh.fromC(xc); err != nil { + return err + } + x.TypeUnion = typePvh + default: + return fmt.Errorf("invalid union key '%v'", x.Type) + } x.ArchArm.GicVersion = GicVersion(xc.arch_arm.gic_version) x.ArchArm.Vuart = VuartType(xc.arch_arm.vuart) x.Altp2M = Altp2MMode(xc.altp2m) @@ -347,6 +408,151 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error { return nil } +func (x *DomainBuildInfoTypeUnionHvm) fromC(xc *C.libxl_domain_build_info) error { + if DomainType(xc._type) != DomainTypeHvm { + return errors.New("expected union key DomainTypeHvm") + } + + tmp := (*C.libxl_domain_build_info_type_union_hvm)(unsafe.Pointer(&xc.u[0])) + x.Firmware = C.GoString(tmp.firmware) + x.Bios = BiosType(tmp.bios) + if err := x.Pae.fromC(&tmp.pae); err != nil { + return err + } + if err := x.Apic.fromC(&tmp.apic); err != nil { + return err + } + if err := x.Acpi.fromC(&tmp.acpi); err != nil { + return err + } + if err := x.AcpiS3.fromC(&tmp.acpi_s3); err != nil { + return err + } + if err := x.AcpiS4.fromC(&tmp.acpi_s4); err != nil { + return err + } + if err := x.AcpiLaptopSlate.fromC(&tmp.acpi_laptop_slate); err != nil { + return err + } + if err := x.Nx.fromC(&tmp.nx); err != nil { + return err + } + if err := x.Viridian.fromC(&tmp.viridian); err != nil { + return err + } + if err := x.ViridianEnable.fromC(&tmp.viridian_enable); err != nil { + return err + } + if err := x.ViridianDisable.fromC(&tmp.viridian_disable); err != nil { + return err + } + x.Timeoffset = C.GoString(tmp.timeoffset) + if err := x.Hpet.fromC(&tmp.hpet); err != nil { + return err + } + if err := x.VptAlign.fromC(&tmp.vpt_align); err != nil { + return err + } + x.MmioHoleMemkb = uint64(tmp.mmio_hole_memkb) + x.TimerMode = TimerMode(tmp.timer_mode) + if err := x.NestedHvm.fromC(&tmp.nested_hvm); err != nil { + return err + } + if err := x.Altp2M.fromC(&tmp.altp2m); err != nil { + return err + } + x.SystemFirmware = C.GoString(tmp.system_firmware) + x.SmbiosFirmware = C.GoString(tmp.smbios_firmware) + x.AcpiFirmware = C.GoString(tmp.acpi_firmware) + x.Hdtype = Hdtype(tmp.hdtype) + if err := x.Nographic.fromC(&tmp.nographic); err != nil { + return err + } + if err := x.Vga.fromC(&tmp.vga); err != nil { + return err + } + if err := x.Vnc.fromC(&tmp.vnc); err != nil { + return err + } + x.Keymap = C.GoString(tmp.keymap) + if err := x.Sdl.fromC(&tmp.sdl); err != nil { + return err + } + if err := x.Spice.fromC(&tmp.spice); err != nil { + return err + } + if err := x.GfxPassthru.fromC(&tmp.gfx_passthru); err != nil { + return err + } + x.GfxPassthruKind = GfxPassthruKind(tmp.gfx_passthru_kind) + x.Serial = C.GoString(tmp.serial) + x.Boot = C.GoString(tmp.boot) + if err := x.Usb.fromC(&tmp.usb); err != nil { + return err + } + x.Usbversion = int(tmp.usbversion) + x.Usbdevice = C.GoString(tmp.usbdevice) + if err := x.VkbDevice.fromC(&tmp.vkb_device); err != nil { + return err + } + x.Soundhw = C.GoString(tmp.soundhw) + if err := x.XenPlatformPci.fromC(&tmp.xen_platform_pci); err != nil { + return err + } + if err := x.UsbdeviceList.fromC(&tmp.usbdevice_list); err != nil { + return err + } + x.VendorDevice = VendorDevice(tmp.vendor_device) + if err := x.MsVmGenid.fromC(&tmp.ms_vm_genid); err != nil { + return err + } + if err := x.SerialList.fromC(&tmp.serial_list); err != nil { + return err + } + if err := x.Rdm.fromC(&tmp.rdm); err != nil { + return err + } + x.RdmMemBoundaryMemkb = uint64(tmp.rdm_mem_boundary_memkb) + x.McaCaps = uint64(tmp.mca_caps) + return nil +} + +func (x *DomainBuildInfoTypeUnionPv) fromC(xc *C.libxl_domain_build_info) error { + if DomainType(xc._type) != DomainTypePv { + return errors.New("expected union key DomainTypePv") + } + + tmp := (*C.libxl_domain_build_info_type_union_pv)(unsafe.Pointer(&xc.u[0])) + x.Kernel = C.GoString(tmp.kernel) + x.SlackMemkb = uint64(tmp.slack_memkb) + x.Bootloader = C.GoString(tmp.bootloader) + if err := x.BootloaderArgs.fromC(&tmp.bootloader_args); err != nil { + return err + } + x.Cmdline = C.GoString(tmp.cmdline) + x.Ramdisk = C.GoString(tmp.ramdisk) + x.Features = C.GoString(tmp.features) + if err := x.E820Host.fromC(&tmp.e820_host); err != nil { + return err + } + return nil +} + +func (x *DomainBuildInfoTypeUnionPvh) fromC(xc *C.libxl_domain_build_info) error { + if DomainType(xc._type) != DomainTypePvh { + return errors.New("expected union key DomainTypePvh") + } + + tmp := (*C.libxl_domain_build_info_type_union_pvh)(unsafe.Pointer(&xc.u[0])) + if err := x.Pvshim.fromC(&tmp.pvshim); err != nil { + return err + } + x.PvshimPath = C.GoString(tmp.pvshim_path) + x.PvshimCmdline = C.GoString(tmp.pvshim_cmdline) + x.PvshimExtra = C.GoString(tmp.pvshim_extra) + return nil +} + func (x *DeviceVfb) fromC(xc *C.libxl_device_vfb) error { x.BackendDomid = Domid(xc.backend_domid) x.BackendDomname = C.GoString(xc.backend_domname) @@ -520,10 +726,32 @@ func (x *DeviceUsbctrl) fromC(xc *C.libxl_device_usbctrl) error { func (x *DeviceUsbdev) fromC(xc *C.libxl_device_usbdev) error { x.Ctrl = Devid(xc.ctrl) x.Port = int(xc.port) + x.Type = UsbdevType(xc._type) + switch x.Type { + case UsbdevTypeHostdev: + var typeHostdev DeviceUsbdevTypeUnionHostdev + if err := typeHostdev.fromC(xc); err != nil { + return err + } + x.TypeUnion = typeHostdev + default: + return fmt.Errorf("invalid union key '%v'", x.Type) + } return nil } +func (x *DeviceUsbdevTypeUnionHostdev) fromC(xc *C.libxl_device_usbdev) error { + if UsbdevType(xc._type) != UsbdevTypeHostdev { + return errors.New("expected union key UsbdevTypeHostdev") + } + + tmp := (*C.libxl_device_usbdev_type_union_hostdev)(unsafe.Pointer(&xc.u[0])) + x.Hostbus = byte(tmp.hostbus) + x.Hostaddr = byte(tmp.hostaddr) + return nil +} + func (x *DeviceDtdev) fromC(xc *C.libxl_device_dtdev) error { x.Path = C.GoString(xc.path) @@ -565,7 +793,28 @@ func (x *DeviceChannel) fromC(xc *C.libxl_device_channel) error { x.BackendDomname = C.GoString(xc.backend_domname) x.Devid = Devid(xc.devid) x.Name = C.GoString(xc.name) + x.Connection = ChannelConnection(xc.connection) + switch x.Connection { + case ChannelConnectionSocket: + var connectionSocket DeviceChannelConnectionUnionSocket + if err := connectionSocket.fromC(xc); err != nil { + return err + } + x.ConnectionUnion = connectionSocket + default: + return fmt.Errorf("invalid union key '%v'", x.Connection) + } + + return nil +} +func (x *DeviceChannelConnectionUnionSocket) fromC(xc *C.libxl_device_channel) error { + if ChannelConnection(xc.connection) != ChannelConnectionSocket { + return errors.New("expected union key ChannelConnectionSocket") + } + + tmp := (*C.libxl_device_channel_connection_union_socket)(unsafe.Pointer(&xc.u[0])) + x.Path = C.GoString(tmp.path) return nil } @@ -881,7 +1130,63 @@ func (x *Event) fromC(xc *C.libxl_event) error { return err } x.ForUser = uint64(xc.for_user) + x.Type = EventType(xc._type) + switch x.Type { + case EventTypeOperationComplete: + var typeOperationComplete EventTypeUnionOperationComplete + if err := typeOperationComplete.fromC(xc); err != nil { + return err + } + x.TypeUnion = typeOperationComplete + case EventTypeDomainShutdown: + var typeDomainShutdown EventTypeUnionDomainShutdown + if err := typeDomainShutdown.fromC(xc); err != nil { + return err + } + x.TypeUnion = typeDomainShutdown + case EventTypeDiskEject: + var typeDiskEject EventTypeUnionDiskEject + if err := typeDiskEject.fromC(xc); err != nil { + return err + } + x.TypeUnion = typeDiskEject + default: + return fmt.Errorf("invalid union key '%v'", x.Type) + } + + return nil +} + +func (x *EventTypeUnionDomainShutdown) fromC(xc *C.libxl_event) error { + if EventType(xc._type) != EventTypeDomainShutdown { + return errors.New("expected union key EventTypeDomainShutdown") + } + tmp := (*C.libxl_event_type_union_domain_shutdown)(unsafe.Pointer(&xc.u[0])) + x.ShutdownReason = byte(tmp.shutdown_reason) + return nil +} + +func (x *EventTypeUnionDiskEject) fromC(xc *C.libxl_event) error { + if EventType(xc._type) != EventTypeDiskEject { + return errors.New("expected union key EventTypeDiskEject") + } + + tmp := (*C.libxl_event_type_union_disk_eject)(unsafe.Pointer(&xc.u[0])) + x.Vdev = C.GoString(tmp.vdev) + if err := x.Disk.fromC(&tmp.disk); err != nil { + return err + } + return nil +} + +func (x *EventTypeUnionOperationComplete) fromC(xc *C.libxl_event) error { + if EventType(xc._type) != EventTypeOperationComplete { + return errors.New("expected union key EventTypeOperationComplete") + } + + tmp := (*C.libxl_event_type_union_operation_complete)(unsafe.Pointer(&xc.u[0])) + x.Rc = int(tmp.rc) return nil } @@ -896,6 +1201,47 @@ func (x *PsrCatInfo) fromC(xc *C.libxl_psr_cat_info) error { func (x *PsrHwInfo) fromC(xc *C.libxl_psr_hw_info) error { x.Id = uint32(xc.id) + x.Type = PsrFeatType(xc._type) + switch x.Type { + case PsrFeatTypeMba: + var typeMba PsrHwInfoTypeUnionMba + if err := typeMba.fromC(xc); err != nil { + return err + } + x.TypeUnion = typeMba + case PsrFeatTypeCat: + var typeCat PsrHwInfoTypeUnionCat + if err := typeCat.fromC(xc); err != nil { + return err + } + x.TypeUnion = typeCat + default: + return fmt.Errorf("invalid union key '%v'", x.Type) + } + + return nil +} + +func (x *PsrHwInfoTypeUnionCat) fromC(xc *C.libxl_psr_hw_info) error { + if PsrFeatType(xc._type) != PsrFeatTypeCat { + return errors.New("expected union key PsrFeatTypeCat") + } + + tmp := (*C.libxl_psr_hw_info_type_union_cat)(unsafe.Pointer(&xc.u[0])) + x.CosMax = uint32(tmp.cos_max) + x.CbmLen = uint32(tmp.cbm_len) + x.CdpEnabled = bool(tmp.cdp_enabled) + return nil +} + +func (x *PsrHwInfoTypeUnionMba) fromC(xc *C.libxl_psr_hw_info) error { + if PsrFeatType(xc._type) != PsrFeatTypeMba { + return errors.New("expected union key PsrFeatTypeMba") + } + tmp := (*C.libxl_psr_hw_info_type_union_mba)(unsafe.Pointer(&xc.u[0])) + x.CosMax = uint32(tmp.cos_max) + x.ThrtlMax = uint32(tmp.thrtl_max) + x.Linear = bool(tmp.linear) return nil }