blob: 80ae5595a71523209467138142b426c2ede7b9e4 [file]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_LIB_DDK_INCLUDE_LIB_DDK_BINDING_PRIV_H_
#define SRC_LIB_DDK_INCLUDE_LIB_DDK_BINDING_PRIV_H_
#include <assert.h>
#include <stdalign.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <zircon/compiler.h>
__BEGIN_CDECLS
// LINT.IfChange
// global binding variables at 0x00XX
// BIND_FLAGS was 0x0000, the value of the flags register
// #define BIND_PROTOCOL 0x0001 // primary protocol of the device
// BIND_AUTOBIND was 0x0002, if this is an automated bind/load
// BIND_COMPOSITE was 0x003, whether this is a composite device
// pci binding variables at 0x01XX
// BIND_PCI_VID was 0x0100
// BIND_PCI_DID was 0x0101
// BIND_PCI_CLASS was 0x0102
// BIND_PCI_SUBCLASS was 0x0103
// BIND_PCI_INTERFACE was 0x0104
// BIND_PCI_REVISION was 0x0105
// BIND_PCI_TOPO was 0x0107
#define BIND_PCI_TOPO_PACK(bus, dev, func) (((bus) << 8) | (dev << 3) | (func))
// usb binding variables at 0x02XX
// these are used for both ZX_PROTOCOL_USB_INTERFACE and ZX_PROTOCOL_USB_FUNCTION
// BIND_USB_VID as 0x0200
// BIND_USB_PID as 0x0201
// BIND_USB_CLASS as 0x0202
// BIND_USB_SUBCLASS as 0x0203
// BIND_USB_PROTOCOL as 0x0204
// BIND_USB_INTERFACE_NUMBER as 0x0205
// Platform bus binding variables at 0x03XX
// BIND_PLATFORM_DEV_VID was 0x0300
// BIND_PLATFORM_DEV_PID was 0x0301
// BIND_PLATFORM_DEV_DID was 0x0302
// BIND_PLATFORM_DEV_INSTANCE_ID was 0x0304
// BIND_PLATFORM_DEV_INTERRUPT_ID was 0x0305
// ACPI binding variables at 0x04XX
// BIND_ACPI_BUS_TYPE was 0x0400
// Internal use only.
// BIND_ACPI_ID was 0x0401
// Intel HDA Codec binding variables at 0x05XX
// BIND_IHDA_CODEC_VID as 0x0500
// BIND_IHDA_CODEC_DID as 0x0501
// BIND_IHDA_CODEC_MAJOR_REV as 0x0502
// BIND_IHDA_CODEC_MINOR_REV as 0x0503
// BIND_IHDA_CODEC_VENDOR_REV as 0x0504
// BIND_IHDA_CODEC_VENDOR_STEP as 0x0505
// Serial binding variables at 0x06XX
// BIND_SERIAL_CLASS was 0x0600
// BIND_SERIAL_VID was 0x0601
// BIND_SERIAL_PID was 0x0602
// NAND binding variables at 0x07XX
// BIND_NAND_CLASS was 0x0700
// SDIO binding variables at 0x09XX
// BIND_SDIO_VID was 0x0900
// BIND_SDIO_PID was 0x0901
// BIND_SDIO_FUNCTION was 0x0902
// I2C binding variables at 0x0A0X
// BIND_I2C_CLASS was 0x0A00
// BIND_I2C_BUS_ID was 0x0A01
// BIND_I2C_ADDRESS was 0x0A02
// BIND_I2C_VID was 0x0A03
// BIND_I2C_DID was 0x0A04
// GPIO binding variables at 0x0A1X
// BIND_GPIO_PIN was 0x0A10
// BIND_GPIO_CONTROLLER was 0x0A11
// POWER binding variables at 0x0A2X
// BIND_POWER_DOMAIN was 0x0A20
// BIND_POWER_DOMAIN_COMPOSITE was 0x0A21
// POWER binding variables at 0x0A3X
// BIND_CLOCK_ID was 0x0A30
// SPI binding variables at 0x0A4X
// BIND_SPI_BUS_ID was 0x0A41
// BIND_SPI_CHIP_SELECT was 0x0A42
// PWM binding variables at 0x0A5X
// BIND_PWM_ID was 0x0A50
// Init Step binding variables at 0x0A6X
// BIND_INIT_STEP was 0x0A60
// Codec binding variables at 0x0A7X
// BIND_CODEC_INSTANCE was 0x0A70
// 0x0A80 was BIND_REGISTER_ID which is now deprecated.
// Power sensor binding variables at 0x0A9X
// BIND_POWER_SENSOR_DOMAIN was 0x0A90
// LINT.ThenChange(/sdk/lib/driver/legacy-bind-constants/legacy-bind-constants.h)
#define ZIRCON_NOTE_NAME "Zircon"
#define ZIRCON_NOTE_DRIVER 0x31565244 // DRV1
typedef struct {
// Elf64_Nhdr fields:
uint32_t namesz;
uint32_t descsz;
uint32_t type;
// ELF note name. namesz is the exact size of the name (including '\0'),
// but the storage size is always rounded up to a multiple of 4 bytes.
char name[(sizeof(ZIRCON_NOTE_NAME) + 3) & -4];
} zircon_driver_note_header_t;
#define ZIRCON_DRIVER_NOTE_HEADER_INIT(object) \
{ \
/* .namesz = */ sizeof(ZIRCON_NOTE_NAME), \
/* .descsz = */ (sizeof(object) - sizeof(zircon_driver_note_header_t)), \
/* .type = */ ZIRCON_NOTE_DRIVER, \
/* .name = */ ZIRCON_NOTE_NAME, \
}
typedef struct {
// See flag bits below.
uint32_t flags;
// Driver Metadata
uint32_t reserved0;
char name[32];
char vendor[16];
char version[16];
} zircon_driver_note_payload_t;
// Flag bits in the driver note:
// Driver is built with `-fsanitize=address` and can only be loaded into a
// devhost that supports the ASan runtime.
#define ZIRCON_DRIVER_NOTE_FLAG_ASAN (1u << 0)
#define ZIRCON_DRIVER_NOTE_PAYLOAD_INIT(Driver, VendorName, Version) \
{ \
/* .flags = */ ZIRCON_DRIVER_NOTE_FLAGS, \
/* .reserved0 = */ 0, \
/* .name = */ #Driver, \
/* .vendor = */ VendorName, \
/* .version = */ Version, \
}
#define ZIRCON_DRIVER_NOTE_FLAGS \
(__has_feature(address_sanitizer) ? ZIRCON_DRIVER_NOTE_FLAG_ASAN : 0)
typedef struct {
zircon_driver_note_header_t header;
zircon_driver_note_payload_t payload;
} zircon_driver_note_t;
static_assert(offsetof(zircon_driver_note_t, payload) == sizeof(zircon_driver_note_header_t),
"alignment snafu?");
// Without this, ASan will add redzone padding after the object, which
// would make it invalid ELF note format.
#if __has_feature(address_sanitizer)
#define ZIRCON_DRIVER_NOTE_ASAN __attribute__((no_sanitize("address")))
#else
#define ZIRCON_DRIVER_NOTE_ASAN
#endif
// GCC has a quirk about how '__attribute__((visibility("default")))'
// (__EXPORT here) works for const variables in C++. The attribute has no
// effect when used on the definition of a const variable, and GCC gives a
// warning/error about that. The attribute must appear on the "extern"
// declaration of the variable instead.
// We explicitly align the note to 4 bytes. That's its natural alignment
// anyway, but the compilers sometimes like to over-align as an
// optimization while other tools sometimes like to complain if SHT_NOTE
// sections are over-aligned (since this could result in padding being
// inserted that makes it violate the ELF note format). Standard C11
// doesn't permit alignas(...) on a type but we could use __ALIGNED(4) on
// all the types (i.e. GNU __attribute__ syntax instead of C11 syntax).
// But the alignment of the types is not actually the issue: it's the
// compiler deciding to over-align the individual object regardless of its
// type's alignment, so we have to explicitly set the alignment of the
// object to defeat any compiler default over-alignment.
// C macro for driver binding rules. Unlike the old bytecode format, the
// instructions in the new format are not represented by three uint32 integers.
// To support both formats simultaneously, |binding| is used for the old
// bytecode instructions while |bytecode| is used for the new bytecode
// instructions.
#define ZIRCON_DRIVER_PRIV(Driver, Ops, VendorName, Version) \
zx_driver_rec_t __zircon_driver_rec__ __EXPORT = { \
/* .ops = */ &(Ops), \
/* .driver = */ NULL, \
}; \
extern const struct zircon_driver_note __zircon_driver_note__ __EXPORT; \
alignas(4) __SECTION(".note.zircon.driver." #Driver) \
ZIRCON_DRIVER_NOTE_ASAN const struct zircon_driver_note { \
zircon_driver_note_t note; \
} __zircon_driver_note__ = { \
/* .note = */ {ZIRCON_DRIVER_NOTE_HEADER_INIT(__zircon_driver_note__), \
ZIRCON_DRIVER_NOTE_PAYLOAD_INIT(Driver, VendorName, Version)}}
// TODO: if we moved the Ops from the BEGIN() to END() macro we
// could add a zircon_driver_note_t* to the zx_driver_rec_t,
// define it in END(), and have only one symbol to dlsym()
// when loading drivers
__END_CDECLS
#endif // SRC_LIB_DDK_INCLUDE_LIB_DDK_BINDING_PRIV_H_