mirror of
https://github.com/AuxXxilium/redpill-lkm5.git
synced 2024-11-23 15:01:01 +07:00
203 lines
6.7 KiB
C
203 lines
6.7 KiB
C
#ifndef REDPILL_VIRTUAL_PCI_H
|
|
#define REDPILL_VIRTUAL_PCI_H
|
|
|
|
#include <linux/types.h>
|
|
|
|
/*
|
|
* The following macros are useful for converting PCI_CLASS_* constants to individual values in structs
|
|
* 31 .................. 0
|
|
* [class][sub][prog][rev] (each is 8 bit number, often times class-sub-prog is represented as on 24-bit int)
|
|
*
|
|
* For more information see header comment in the corresponding .c file.
|
|
*/
|
|
#define U24_CLASS_TO_U8_CLASS(x) (((x) >> 16) & 0xFF)
|
|
#define U24_CLASS_TO_U8_SUBCLASS(x) (((x) >> 8) & 0xFF)
|
|
#define U24_CLASS_TO_U8_PROGIF(x) ((x) & 0xFF)
|
|
#define U16_CLASS_TO_U8_CLASS(x) (((x) >> 8) & 0xFF)
|
|
#define U16_CLASS_TO_U8_SUBCLASS(x) ((x) & 0xFF)
|
|
|
|
//Some helpful constants on top of what's in linux/pci_ids.h & linux/pci_regs.h
|
|
#define PCI_DSC_NO_INT_LINE 0xFF
|
|
#define PCI_DSC_NO_INT_PIN 0x00
|
|
#define PCI_DSC_PROGIF_NONE 0x00
|
|
#define PCI_DSC_REV_NONE 0x00
|
|
#define PCI_DSC_NULL_BAR 0x00000000
|
|
#define PCI_DSC_NULL_CAP 0x00
|
|
#define PCI_DSC_RSV8 0x00
|
|
#define PCI_DSC_RSV16 0x0000
|
|
#define PCI_DSC_INF_LATENCY 0xFF //i.e. accepts any latency in access
|
|
#define PCI_DSC_ZERO_BURST 0xFF //i.e. doesn't need any length of burst
|
|
#define PCI_DSC_BIST_NONE 0x00
|
|
|
|
//See https://en.wikipedia.org/wiki/PCI_configuration_space#/media/File:Pci-config-space.svg
|
|
//This struct MUST be packed to allow for easy reading, see https://kernelnewbies.org/DataAlignment
|
|
struct pci_dev_descriptor {
|
|
u16 vid; //Vendor ID
|
|
u16 dev; //Device ID
|
|
|
|
u16 command; //see PCI_COMMAND_*. Simply do "dev.command |= PCI_COMMAND_xxx" to set a flag.
|
|
u16 status; //see PCI_STATUS_*. Simply do "dev.status |= PCI_STATUS_xxx" to set a flag.
|
|
|
|
u8 rev_id;
|
|
u8 prog_if; // ]
|
|
u8 subclass; // ]-> prof_if, subclass, and class are normally represented as 24-bit class code
|
|
u8 class; // ]
|
|
|
|
u8 cache_line_size;
|
|
u8 latency_timer;
|
|
u8 header_type; //see PCI_HEADER_TYPE_*
|
|
u8 bist; //see PCI_BIST_*
|
|
|
|
u32 bar0;
|
|
u32 bar1;
|
|
u32 bar2;
|
|
u32 bar3;
|
|
u32 bar4;
|
|
u32 bar5;
|
|
|
|
u32 cardbus_cis;
|
|
|
|
u16 subsys_vid;
|
|
u16 subsys_id;
|
|
|
|
u32 exp_rom_base_addr; //see PCI_ROM_* (esp PCI_ROM_ADDRESS_MASK)
|
|
|
|
u8 cap_ptr;
|
|
u8 reserved_34_8_15; //should be 0x00
|
|
u16 reserved_34_16_31; //should be 0x00
|
|
|
|
u32 reserved_38h;
|
|
|
|
u8 interrupt_line;
|
|
u8 interrupt_pin;
|
|
u8 min_gnt;
|
|
u8 max_lat;
|
|
} __packed;
|
|
extern const struct pci_dev_descriptor pci_dev_conf_default_normal_dev; //See details in the .c file
|
|
|
|
//Support for bridges wasn't tested
|
|
struct pci_pci_bridge_descriptor {
|
|
u16 vid; //Vendor ID
|
|
u16 dev; //Device ID
|
|
|
|
u16 command; //see PCI_COMMAND_*. Simply do "dev.command |= PCI_COMMAND_xxx" to set a flag.
|
|
u16 status; //see PCI_STATUS_*. Simply do "dev.status |= PCI_STATUS_xxx" to set a flag.
|
|
|
|
u8 rev_id;
|
|
u8 prog_if; // ]
|
|
u8 subclass; // ]-> prof_if, subclass, and class are normally represented as 24-bit class code
|
|
u8 class; // ]
|
|
|
|
u8 cache_line_size;
|
|
u8 latency_timer;
|
|
u8 header_type; //see PCI_HEADER_TYPE_*
|
|
u8 bist; //see PCI_BIST_*
|
|
|
|
u32 bar0;
|
|
u32 bar1;
|
|
|
|
u8 pri_bus_no;
|
|
u8 sec_bus_no;
|
|
u8 subord_bus_no;
|
|
u8 sec_lat_timer;
|
|
|
|
u8 io_base;
|
|
u8 io_limit;
|
|
u16 sec_status;
|
|
|
|
u16 mem_base;
|
|
u16 mem_limit;
|
|
|
|
u16 prefetch_mem_base;
|
|
u16 prefetch_mem_limit;
|
|
|
|
u32 prefetch_base_up32b;
|
|
u32 prefetch_limit_up32b;
|
|
|
|
u16 io_base_up16b;
|
|
u16 io_limit_up16b;
|
|
|
|
u8 cap_ptr;
|
|
u8 reserved_34_8_15; //should be 0x00
|
|
u16 reserved_34_16_31; //should be 0x00
|
|
|
|
u32 exp_rom_base_addr; //see PCI_ROM_* (esp PCI_ROM_ADDRESS_MASK)
|
|
|
|
u8 interrupt_line;
|
|
u8 interrupt_pin;
|
|
u16 bridge_ctrl;
|
|
} __packed;
|
|
|
|
//This is currently not implemented
|
|
struct pci_dev_capability {
|
|
u8 cap_id; //see PCI_CAP_ID_*, set to 0x00 to denote null-capability
|
|
u8 cap_next; //offset where next capability exists, set to 0x00 to denote null-capability
|
|
u8 cap_data[];
|
|
} __packed;
|
|
|
|
/**
|
|
* Adds a single new device (along with the bus if needed)
|
|
*
|
|
* If you don't want to create the descriptor from scratch you can use "const struct pci_dev_conf_default_normal_dev"
|
|
* while setting some missing params (see .c file header for details).
|
|
* Note: you CAN reuse the same descriptor under multiple BDFs (bus_no/dev_no/fn_no)
|
|
*
|
|
* @param bus_no (0x00 - 0xFF)
|
|
* @param dev_no (0x00 - 0x20)
|
|
* @param descriptor Pointer to pci_dev_descriptor or pci_pci_bridge_descriptor
|
|
* @return virtual_device ptr or error pointer (ERR_PTR(-E))
|
|
*/
|
|
const struct virtual_device *
|
|
vpci_add_single_device(unsigned char bus_no, unsigned char dev_no, struct pci_dev_descriptor *descriptor);
|
|
|
|
/**
|
|
* See vpci_add_single_device() for details
|
|
*/
|
|
const struct virtual_device *
|
|
vpci_add_single_bridge(unsigned char bus_no, unsigned char dev_no, struct pci_pci_bridge_descriptor *descriptor);
|
|
|
|
|
|
/*
|
|
* Adds a new multifunction device (along with the bus if needed)
|
|
*
|
|
* Warning about multifunctional devices
|
|
* - this function has a slight limitation due to how Linux scans devices. You HAVE TO add fn_no=0 entry as the LAST
|
|
* one when calling it multiple times. Kernel scans devices only once for changes and if it finds fn=0 and it's the
|
|
* only one (i.e. you added fn=0 first) adding more functions will not populate them (as kernel will never re-scan
|
|
* the device).
|
|
* - As per PCI spec Linux doesn't allow devices to have fn>0 if they don't have corresponding fn=0 entry
|
|
*
|
|
* @param bus_no (0x00 - 0xFF)
|
|
* @param dev_no (0x00 - 0x20)
|
|
* @param fn_no (0x00 - 0x07)
|
|
* @param descriptor Pointer to pci_dev_descriptor or pci_pci_bridge_descriptor
|
|
* @return virtual_device ptr or error pointer (ERR_PTR(-E))
|
|
*/
|
|
const struct virtual_device *
|
|
vpci_add_multifunction_device(unsigned char bus_no, unsigned char dev_no, unsigned char fn_no,
|
|
struct pci_dev_descriptor *descriptor);
|
|
|
|
/**
|
|
* See vpci_add_multifunction_device() for details
|
|
*/
|
|
const struct virtual_device *
|
|
vpci_add_multifunction_bridge(unsigned char bus_no, unsigned char dev_no, unsigned char fn_no,
|
|
struct pci_pci_bridge_descriptor *descriptor);
|
|
|
|
/**
|
|
* Removes all previously added devices and buses
|
|
*
|
|
* Known bug: while you can remove things and they will be gone from the system you CANNOT re-add the same under the
|
|
* same BFD coordinates. This will cause the kernel to complain about duplicated internal sysfs entries. It's most
|
|
* likely an old kernel bug (we tried everything... it doesn't work).
|
|
*
|
|
* @param bus_no
|
|
* @param dev_no
|
|
* @param fn_no
|
|
* @param descriptor
|
|
* @return
|
|
*/
|
|
int vpci_remove_all_devices_and_buses(void);
|
|
|
|
#endif //REDPILL_VIRTUAL_PCI_H
|