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

gelic_udbg.c (5723B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * udbg debug output routine via GELIC UDP broadcasts
      4 *
      5 * Copyright (C) 2007 Sony Computer Entertainment Inc.
      6 * Copyright 2006, 2007 Sony Corporation
      7 * Copyright (C) 2010 Hector Martin <hector@marcansoft.com>
      8 * Copyright (C) 2011 Andre Heider <a.heider@gmail.com>
      9 */
     10
     11#include <linux/if_ether.h>
     12#include <linux/etherdevice.h>
     13#include <linux/if_vlan.h>
     14#include <linux/ip.h>
     15#include <linux/udp.h>
     16
     17#include <asm/io.h>
     18#include <asm/udbg.h>
     19#include <asm/lv1call.h>
     20
     21#define GELIC_BUS_ID 1
     22#define GELIC_DEVICE_ID 0
     23#define GELIC_DEBUG_PORT 18194
     24#define GELIC_MAX_MESSAGE_SIZE 1000
     25
     26#define GELIC_LV1_GET_MAC_ADDRESS 1
     27#define GELIC_LV1_GET_VLAN_ID 4
     28#define GELIC_LV1_VLAN_TX_ETHERNET_0 2
     29
     30#define GELIC_DESCR_DMA_STAT_MASK 0xf0000000
     31#define GELIC_DESCR_DMA_CARDOWNED 0xa0000000
     32
     33#define GELIC_DESCR_TX_DMA_IKE 0x00080000
     34#define GELIC_DESCR_TX_DMA_NO_CHKSUM 0x00000000
     35#define GELIC_DESCR_TX_DMA_FRAME_TAIL 0x00040000
     36
     37#define GELIC_DESCR_DMA_CMD_NO_CHKSUM (GELIC_DESCR_DMA_CARDOWNED | \
     38				       GELIC_DESCR_TX_DMA_IKE | \
     39				       GELIC_DESCR_TX_DMA_NO_CHKSUM)
     40
     41static u64 bus_addr;
     42
     43struct gelic_descr {
     44	/* as defined by the hardware */
     45	__be32 buf_addr;
     46	__be32 buf_size;
     47	__be32 next_descr_addr;
     48	__be32 dmac_cmd_status;
     49	__be32 result_size;
     50	__be32 valid_size;	/* all zeroes for tx */
     51	__be32 data_status;
     52	__be32 data_error;	/* all zeroes for tx */
     53} __attribute__((aligned(32)));
     54
     55struct debug_block {
     56	struct gelic_descr descr;
     57	u8 pkt[1520];
     58} __packed;
     59
     60static __iomem struct ethhdr *h_eth;
     61static __iomem struct vlan_hdr *h_vlan;
     62static __iomem struct iphdr *h_ip;
     63static __iomem struct udphdr *h_udp;
     64
     65static __iomem char *pmsg;
     66static __iomem char *pmsgc;
     67
     68static __iomem struct debug_block dbg __attribute__((aligned(32)));
     69
     70static int header_size;
     71
     72static void map_dma_mem(int bus_id, int dev_id, void *start, size_t len,
     73			u64 *real_bus_addr)
     74{
     75	s64 result;
     76	u64 real_addr = ((u64)start) & 0x0fffffffffffffffUL;
     77	u64 real_end = real_addr + len;
     78	u64 map_start = real_addr & ~0xfff;
     79	u64 map_end = (real_end + 0xfff) & ~0xfff;
     80	u64 bus_addr = 0;
     81
     82	u64 flags = 0xf800000000000000UL;
     83
     84	result = lv1_allocate_device_dma_region(bus_id, dev_id,
     85						map_end - map_start, 12, 0,
     86						&bus_addr);
     87	if (result)
     88		lv1_panic(0);
     89
     90	result = lv1_map_device_dma_region(bus_id, dev_id, map_start,
     91					   bus_addr, map_end - map_start,
     92					   flags);
     93	if (result)
     94		lv1_panic(0);
     95
     96	*real_bus_addr = bus_addr + real_addr - map_start;
     97}
     98
     99static int unmap_dma_mem(int bus_id, int dev_id, u64 bus_addr, size_t len)
    100{
    101	s64 result;
    102	u64 real_bus_addr;
    103
    104	real_bus_addr = bus_addr & ~0xfff;
    105	len += bus_addr - real_bus_addr;
    106	len = (len + 0xfff) & ~0xfff;
    107
    108	result = lv1_unmap_device_dma_region(bus_id, dev_id, real_bus_addr,
    109					     len);
    110	if (result)
    111		return result;
    112
    113	return lv1_free_device_dma_region(bus_id, dev_id, real_bus_addr);
    114}
    115
    116static void __init gelic_debug_init(void)
    117{
    118	s64 result;
    119	u64 v2;
    120	u64 mac;
    121	u64 vlan_id;
    122
    123	result = lv1_open_device(GELIC_BUS_ID, GELIC_DEVICE_ID, 0);
    124	if (result)
    125		lv1_panic(0);
    126
    127	map_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID, &dbg, sizeof(dbg),
    128		    &bus_addr);
    129
    130	memset(&dbg, 0, sizeof(dbg));
    131
    132	dbg.descr.buf_addr = bus_addr + offsetof(struct debug_block, pkt);
    133
    134	wmb();
    135
    136	result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID,
    137				 GELIC_LV1_GET_MAC_ADDRESS, 0, 0, 0,
    138				 &mac, &v2);
    139	if (result)
    140		lv1_panic(0);
    141
    142	mac <<= 16;
    143
    144	h_eth = (struct ethhdr *)dbg.pkt;
    145
    146	eth_broadcast_addr(h_eth->h_dest);
    147	memcpy(&h_eth->h_source, &mac, ETH_ALEN);
    148
    149	header_size = sizeof(struct ethhdr);
    150
    151	result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID,
    152				 GELIC_LV1_GET_VLAN_ID,
    153				 GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0,
    154				 &vlan_id, &v2);
    155	if (!result) {
    156		h_eth->h_proto= ETH_P_8021Q;
    157
    158		header_size += sizeof(struct vlan_hdr);
    159		h_vlan = (struct vlan_hdr *)(h_eth + 1);
    160		h_vlan->h_vlan_TCI = vlan_id;
    161		h_vlan->h_vlan_encapsulated_proto = ETH_P_IP;
    162		h_ip = (struct iphdr *)(h_vlan + 1);
    163	} else {
    164		h_eth->h_proto= 0x0800;
    165		h_ip = (struct iphdr *)(h_eth + 1);
    166	}
    167
    168	header_size += sizeof(struct iphdr);
    169	h_ip->version = 4;
    170	h_ip->ihl = 5;
    171	h_ip->ttl = 10;
    172	h_ip->protocol = 0x11;
    173	h_ip->saddr = 0x00000000;
    174	h_ip->daddr = 0xffffffff;
    175
    176	header_size += sizeof(struct udphdr);
    177	h_udp = (struct udphdr *)(h_ip + 1);
    178	h_udp->source = GELIC_DEBUG_PORT;
    179	h_udp->dest = GELIC_DEBUG_PORT;
    180
    181	pmsgc = pmsg = (char *)(h_udp + 1);
    182}
    183
    184static void gelic_debug_shutdown(void)
    185{
    186	if (bus_addr)
    187		unmap_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID,
    188			      bus_addr, sizeof(dbg));
    189	lv1_close_device(GELIC_BUS_ID, GELIC_DEVICE_ID);
    190}
    191
    192static void gelic_sendbuf(int msgsize)
    193{
    194	u16 *p;
    195	u32 sum;
    196	int i;
    197
    198	dbg.descr.buf_size = header_size + msgsize;
    199	h_ip->tot_len = msgsize + sizeof(struct udphdr) +
    200			     sizeof(struct iphdr);
    201	h_udp->len = msgsize + sizeof(struct udphdr);
    202
    203	h_ip->check = 0;
    204	sum = 0;
    205	p = (u16 *)h_ip;
    206	for (i = 0; i < 5; i++)
    207		sum += *p++;
    208	h_ip->check = ~(sum + (sum >> 16));
    209
    210	dbg.descr.dmac_cmd_status = GELIC_DESCR_DMA_CMD_NO_CHKSUM |
    211				    GELIC_DESCR_TX_DMA_FRAME_TAIL;
    212	dbg.descr.result_size = 0;
    213	dbg.descr.data_status = 0;
    214
    215	wmb();
    216
    217	lv1_net_start_tx_dma(GELIC_BUS_ID, GELIC_DEVICE_ID, bus_addr, 0);
    218
    219	while ((dbg.descr.dmac_cmd_status & GELIC_DESCR_DMA_STAT_MASK) ==
    220	       GELIC_DESCR_DMA_CARDOWNED)
    221		cpu_relax();
    222}
    223
    224static void ps3gelic_udbg_putc(char ch)
    225{
    226	*pmsgc++ = ch;
    227	if (ch == '\n' || (pmsgc-pmsg) >= GELIC_MAX_MESSAGE_SIZE) {
    228		gelic_sendbuf(pmsgc-pmsg);
    229		pmsgc = pmsg;
    230	}
    231}
    232
    233void __init udbg_init_ps3gelic(void)
    234{
    235	gelic_debug_init();
    236	udbg_putc = ps3gelic_udbg_putc;
    237}
    238
    239void udbg_shutdown_ps3gelic(void)
    240{
    241	udbg_putc = NULL;
    242	gelic_debug_shutdown();
    243}
    244EXPORT_SYMBOL(udbg_shutdown_ps3gelic);