cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

module.c (5885B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2
      3/*
      4 * IBM ASM Service Processor Device Driver
      5 *
      6 * Copyright (C) IBM Corporation, 2004
      7 *
      8 * Author: Max Asböck <amax@us.ibm.com>
      9 *
     10 * This driver is based on code originally written by Pete Reynolds
     11 * and others.
     12 */
     13
     14/*
     15 * The ASM device driver does the following things:
     16 *
     17 * 1) When loaded it sends a message to the service processor,
     18 * indicating that an OS is * running. This causes the service processor
     19 * to send periodic heartbeats to the OS.
     20 *
     21 * 2) Answers the periodic heartbeats sent by the service processor.
     22 * Failure to do so would result in system reboot.
     23 *
     24 * 3) Acts as a pass through for dot commands sent from user applications.
     25 * The interface for this is the ibmasmfs file system.
     26 *
     27 * 4) Allows user applications to register for event notification. Events
     28 * are sent to the driver through interrupts. They can be read from user
     29 * space through the ibmasmfs file system.
     30 *
     31 * 5) Allows user space applications to send heartbeats to the service
     32 * processor (aka reverse heartbeats). Again this happens through ibmasmfs.
     33 *
     34 * 6) Handles remote mouse and keyboard event interrupts and makes them
     35 * available to user applications through ibmasmfs.
     36 *
     37 */
     38
     39#include <linux/pci.h>
     40#include <linux/init.h>
     41#include <linux/slab.h>
     42#include "ibmasm.h"
     43#include "lowlevel.h"
     44#include "remote.h"
     45
     46int ibmasm_debug = 0;
     47module_param(ibmasm_debug, int , S_IRUGO | S_IWUSR);
     48MODULE_PARM_DESC(ibmasm_debug, " Set debug mode on or off");
     49
     50
     51static int ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
     52{
     53	int result;
     54	struct service_processor *sp;
     55
     56	if ((result = pci_enable_device(pdev))) {
     57		dev_err(&pdev->dev, "Failed to enable PCI device\n");
     58		return result;
     59	}
     60	if ((result = pci_request_regions(pdev, DRIVER_NAME))) {
     61		dev_err(&pdev->dev, "Failed to allocate PCI resources\n");
     62		goto error_resources;
     63	}
     64	/* vnc client won't work without bus-mastering */
     65	pci_set_master(pdev);
     66
     67	sp = kzalloc(sizeof(struct service_processor), GFP_KERNEL);
     68	if (sp == NULL) {
     69		dev_err(&pdev->dev, "Failed to allocate memory\n");
     70		result = -ENOMEM;
     71		goto error_kmalloc;
     72	}
     73
     74	spin_lock_init(&sp->lock);
     75	INIT_LIST_HEAD(&sp->command_queue);
     76
     77	pci_set_drvdata(pdev, (void *)sp);
     78	sp->dev = &pdev->dev;
     79	sp->number = pdev->bus->number;
     80	snprintf(sp->dirname, IBMASM_NAME_SIZE, "%d", sp->number);
     81	snprintf(sp->devname, IBMASM_NAME_SIZE, "%s%d", DRIVER_NAME, sp->number);
     82
     83	result = ibmasm_event_buffer_init(sp);
     84	if (result) {
     85		dev_err(sp->dev, "Failed to allocate event buffer\n");
     86		goto error_eventbuffer;
     87	}
     88
     89	result = ibmasm_heartbeat_init(sp);
     90	if (result) {
     91		dev_err(sp->dev, "Failed to allocate heartbeat command\n");
     92		goto error_heartbeat;
     93	}
     94
     95	sp->irq = pdev->irq;
     96	sp->base_address = pci_ioremap_bar(pdev, 0);
     97	if (!sp->base_address) {
     98		dev_err(sp->dev, "Failed to ioremap pci memory\n");
     99		result =  -ENODEV;
    100		goto error_ioremap;
    101	}
    102
    103	result = request_irq(sp->irq, ibmasm_interrupt_handler, IRQF_SHARED, sp->devname, (void*)sp);
    104	if (result) {
    105		dev_err(sp->dev, "Failed to register interrupt handler\n");
    106		goto error_request_irq;
    107	}
    108
    109	enable_sp_interrupts(sp->base_address);
    110
    111	result = ibmasm_init_remote_input_dev(sp);
    112	if (result) {
    113		dev_err(sp->dev, "Failed to initialize remote queue\n");
    114		goto error_init_remote;
    115	}
    116
    117	result = ibmasm_send_driver_vpd(sp);
    118	if (result) {
    119		dev_err(sp->dev, "Failed to send driver VPD to service processor\n");
    120		goto error_send_message;
    121	}
    122	result = ibmasm_send_os_state(sp, SYSTEM_STATE_OS_UP);
    123	if (result) {
    124		dev_err(sp->dev, "Failed to send OS state to service processor\n");
    125		goto error_send_message;
    126	}
    127	ibmasmfs_add_sp(sp);
    128
    129	ibmasm_register_uart(sp);
    130
    131	return 0;
    132
    133error_send_message:
    134	ibmasm_free_remote_input_dev(sp);
    135error_init_remote:
    136	disable_sp_interrupts(sp->base_address);
    137	free_irq(sp->irq, (void *)sp);
    138error_request_irq:
    139	iounmap(sp->base_address);
    140error_ioremap:
    141	ibmasm_heartbeat_exit(sp);
    142error_heartbeat:
    143	ibmasm_event_buffer_exit(sp);
    144error_eventbuffer:
    145	kfree(sp);
    146error_kmalloc:
    147        pci_release_regions(pdev);
    148error_resources:
    149        pci_disable_device(pdev);
    150
    151	return result;
    152}
    153
    154static void ibmasm_remove_one(struct pci_dev *pdev)
    155{
    156	struct service_processor *sp = pci_get_drvdata(pdev);
    157
    158	dbg("Unregistering UART\n");
    159	ibmasm_unregister_uart(sp);
    160	dbg("Sending OS down message\n");
    161	if (ibmasm_send_os_state(sp, SYSTEM_STATE_OS_DOWN))
    162		err("failed to get response to 'Send OS State' command\n");
    163	dbg("Disabling heartbeats\n");
    164	ibmasm_heartbeat_exit(sp);
    165	dbg("Disabling interrupts\n");
    166	disable_sp_interrupts(sp->base_address);
    167	dbg("Freeing SP irq\n");
    168	free_irq(sp->irq, (void *)sp);
    169	dbg("Cleaning up\n");
    170	ibmasm_free_remote_input_dev(sp);
    171	iounmap(sp->base_address);
    172	ibmasm_event_buffer_exit(sp);
    173	kfree(sp);
    174	pci_release_regions(pdev);
    175	pci_disable_device(pdev);
    176}
    177
    178static struct pci_device_id ibmasm_pci_table[] =
    179{
    180	{ PCI_DEVICE(VENDORID_IBM, DEVICEID_RSA) },
    181	{},
    182};
    183
    184static struct pci_driver ibmasm_driver = {
    185	.name		= DRIVER_NAME,
    186	.id_table	= ibmasm_pci_table,
    187	.probe		= ibmasm_init_one,
    188	.remove		= ibmasm_remove_one,
    189};
    190
    191static void __exit ibmasm_exit (void)
    192{
    193	ibmasm_unregister_panic_notifier();
    194	ibmasmfs_unregister();
    195	pci_unregister_driver(&ibmasm_driver);
    196	info(DRIVER_DESC " version " DRIVER_VERSION " unloaded");
    197}
    198
    199static int __init ibmasm_init(void)
    200{
    201	int result = pci_register_driver(&ibmasm_driver);
    202	if (result)
    203		return result;
    204
    205	result = ibmasmfs_register();
    206	if (result) {
    207		pci_unregister_driver(&ibmasm_driver);
    208		err("Failed to register ibmasmfs file system");
    209		return result;
    210	}
    211
    212	ibmasm_register_panic_notifier();
    213	info(DRIVER_DESC " version " DRIVER_VERSION " loaded");
    214	return 0;
    215}
    216
    217module_init(ibmasm_init);
    218module_exit(ibmasm_exit);
    219
    220MODULE_AUTHOR(DRIVER_AUTHOR);
    221MODULE_DESCRIPTION(DRIVER_DESC);
    222MODULE_LICENSE("GPL");
    223MODULE_DEVICE_TABLE(pci, ibmasm_pci_table);
    224