Execute mmap on Linux kernel - c

I'm trying to enable pull-ups on Raspberry pi and the easier way to do it it's executing raspi-gpio set <gpio> <pu/pd>, the problem is that for some reason I can't do it with call_usermodehelper (it doesn't throw any error, but it does nothing).
As an alternative I've been looking at raspi-gpio source code and I have a functional C code that enables pull-ups (this code prints the GPIO CPU and enable GPIO26's pull-ups):
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
// From https://github.com/RPi-Distro/raspi-gpio/blob/master/raspi-gpio.c
#define PULL_UNSET -1
#define PULL_NONE 0
#define PULL_DOWN 1
#define PULL_UP 2
#define GPIO_BASE_OFFSET 0x00200000
#define GPPUD 37
#define GPPUDCLK0 38
uint32_t getGpioRegBase(void) {
const char *revision_file = "/proc/device-tree/system/linux,revision";
uint8_t revision[4] = { 0 };
uint32_t cpu = 0;
FILE *fd;
if ((fd = fopen(revision_file, "rb")) == NULL)
{
printf("Can't open '%s'\n", revision_file);
}
else
{
if (fread(revision, 1, sizeof(revision), fd) == 4)
cpu = (revision[2] >> 4) & 0xf;
else
printf("Revision data too short\n");
fclose(fd);
}
printf("CPU: %d\n", cpu);
switch (cpu) {
case 0: // BCM2835 [Pi 1 A; Pi 1 B; Pi 1 B+; Pi Zero; Pi Zero W]
return 0x20000000 + GPIO_BASE_OFFSET;
case 1: // BCM2836 [Pi 2 B]
case 2: // BCM2837 [Pi 3 B; Pi 3 B+; Pi 3 A+]
return 0x3f000000 + GPIO_BASE_OFFSET;
case 3: // BCM2711 [Pi 4 B]
return 0xfe000000 + GPIO_BASE_OFFSET;
default:
printf("Unrecognised revision code\n");
exit(1);
}
}
volatile uint32_t *getBase(uint32_t reg_base) {
int fd;
if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0) return NULL;
return (uint32_t *)mmap(0, /*chip->reg_size*/ 0x1000,
PROT_READ|PROT_WRITE, MAP_SHARED,
fd, reg_base);
}
void setPull(volatile uint32_t *base, unsigned int gpio, int pull) {
int clkreg = GPPUDCLK0 + (gpio / 32);
int clkbit = 1 << (gpio % 32);
base[GPPUD] = pull;
usleep(10);
base[clkreg] = clkbit;
usleep(10);
base[GPPUD] = 0;
usleep(10);
base[clkreg] = 0;
usleep(10);
}
int main() {
uint32_t reg_base = getGpioRegBase();
volatile uint32_t *base = getBase(reg_base);
if (base == NULL || base == (uint32_t *)-1) {
printf("Base error");
return 1;
}
printf("Base: %p\n", base);
setPull(base, 26, PULL_UP);
return 0;
}
Now obviously I need to convert that code to kernel code. I've been doing great with delays and files, but I have no idea what to do with mmap (I've never seen it before and I don't know exactly what it does, all I know it's that it maps memory).
#include <linux/types.h> // uint_32
#include <linux/fs.h> // filp_open/filp_close
#include <linux/delay.h> // delay
#define PULL_DOWN 1
#define PULL_UP 2
#define GPIO_BASE_OFFSET 0x00200000
#define GPPUD 37
#define GPPUDCLK0 38
static uint32_t getGpioRegBase(bool *error) {
uint8_t revision[4] = { 0 };
uint32_t cpu = 0;
struct file *fd;
ssize_t rc = 0;
if (IS_ERR(( fd = filp_open("/proc/device-tree/system/linux,revision", O_RDONLY | O_SYNC | O_CLOEXEC, 0) ))) {
*error = true;
return 0;
}
if ((rc = kernel_read(fd, revision, sizeof(revision), 0)) == 4) cpu = (revision[2] >> 4) & 0xf;
else {
*error = true;
return 0;
}
filp_close(fd, NULL);
*error = false;
switch (cpu) {
case 0: // BCM2835 [Pi 1 A; Pi 1 B; Pi 1 B+; Pi Zero; Pi Zero W]
return 0x20000000 + GPIO_BASE_OFFSET;
case 1: // BCM2836 [Pi 2 B]
case 2: // BCM2837 [Pi 3 B; Pi 3 B+; Pi 3 A+]
return 0x3f000000 + GPIO_BASE_OFFSET;
case 3: // BCM2711 [Pi 4 B]
return 0xfe000000 + GPIO_BASE_OFFSET;
default:
*error = true;
return 0;
}
}
static volatile uint32_t *getBase(uint32_t reg_base) {
struct file *fd;
volatile uint32_t *r;
if (IS_ERR(( fd = filp_open("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC, 0) ))) return NULL;
r = (uint32_t*)mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, reg_base);
filp_close(fd, NULL); // TODO the original didn't have this
return r;
}
static void setPull(volatile uint32_t *base, uint32_t gpio, int pull) {
int clkreg = GPPUDCLK0 + (gpio / 32);
int clkbit = 1 << (gpio % 32);
base[GPPUD] = pull;
udelay(10);
base[clkreg] = clkbit;
udelay(10);
base[GPPUD] = 0;
udelay(10);
base[clkreg] = 0;
udelay(10);
}
/**
* Equivalent to 'raspi-gpio set <gpio> <pu/pd>'
* #param gpio Valid GPIO pin
* #param pull PULL_DOWN/PULL_UP
*/
static int setGpioPull(uint32_t gpio, int pull) {
bool error;
uint32_t reg_base;
volatile uint32_t *base;
reg_base = getGpioRegBase(&error);
if (error) return -1;
base = getBase(reg_base);
if (base == NULL || base == (uint32_t*)-1) return -1;
setPull(base, gpio, pull);
return 0;
}
All I've found it's a function declaration (int (*mmap) (struct file *filp, struct vm_area_struct *vma)), but I don't know how to send any of the arguments nor the return value that mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset) uses.
Thanks in advance!

Mmap was accessing to "/dev/mem", after some more questions I've found that that file connects user-space with kernel-space (and LKM it's on kernel space, so no need to access to it). In this case, ioremap does the job.
Here's the final code:
#include <linux/types.h> // uint_32
#include <linux/fs.h> // filp_open/filp_close
#include <linux/delay.h> // udelay
#include <linux/io.h> // ioremap?
#define PULL_DOWN 1
#define PULL_UP 2
/**
* Equivalent to 'raspi-gpio set <gpio> <pu/pd>'
* #param gpio Valid GPIO pin
* #param pull PULL_DOWN/PULL_UP
*/
static int setGpioPull(uint32_t gpio, int pull);
/****************************
*** PRIVATE FUNCTIONS ***
****************************/
#define GPIO_BASE_OFFSET 0x00200000
#define GPPUD 37
#define GPPUDCLK0 38
static uint32_t getGpioRegBase(bool *error) {
uint8_t revision[4] = { 0 };
uint32_t cpu = 0;
struct file *fd;
ssize_t rc = 0;
if (IS_ERR(( fd = filp_open("/proc/device-tree/system/linux,revision", O_RDONLY | O_SYNC | O_CLOEXEC, 0) ))) {
*error = true;
return 0;
}
if ((rc = kernel_read(fd, revision, sizeof(revision), 0)) == 4) cpu = (revision[2] >> 4) & 0xf;
else {
*error = true;
return 0;
}
filp_close(fd, NULL);
*error = false;
switch (cpu) {
case 0: // BCM2835 [Pi 1 A; Pi 1 B; Pi 1 B+; Pi Zero; Pi Zero W]
return 0x20000000 + GPIO_BASE_OFFSET;
case 1: // BCM2836 [Pi 2 B]
case 2: // BCM2837 [Pi 3 B; Pi 3 B+; Pi 3 A+]
return 0x3f000000 + GPIO_BASE_OFFSET;
case 3: // BCM2711 [Pi 4 B]
return 0xfe000000 + GPIO_BASE_OFFSET;
default:
*error = true;
return 0;
}
}
static void setPull(volatile uint32_t *base, uint32_t gpio, int pull) {
int clkreg = GPPUDCLK0 + (gpio / 32);
int clkbit = 1 << (gpio % 32);
base[GPPUD] = pull;
udelay(10);
base[clkreg] = clkbit;
udelay(10);
base[GPPUD] = 0;
udelay(10);
base[clkreg] = 0;
udelay(10);
}
static int setGpioPull(uint32_t gpio, int pull) {
bool error;
uint32_t reg_base;
volatile uint32_t *base;
reg_base = getGpioRegBase(&error);
if (error) return -1;
base = (uint32_t*)ioremap(reg_base, 0x1000);
if (base == NULL || base == (uint32_t*)-1) return -1;
setPull(base, gpio, pull);
iounmap(base);
return 0;
}

Related

interrupts not working in KVM x86 16-bit guest

I'm writing a Linux KVM hypervisor for x86 16-bit guests running in real mode. When doing interrupt calls (int ... instruction), I've encountered the KVM_INTERNAL_ERROR_SIMUL_EX error on Linux kernel 3.13.0. The same code is running fine on Linux kernel 3.16.0. Am I missing something? Is there a workaround I can add to my code to make it work with Linux kernel 3.13.0 (and possibly earlier)?
The test guest calls int 0x18 ... int 0x4f, all of which is handled in the hypervisor (C code after KVM_RUN has returned). When it's working correctly, all of the interrupt calls work. On Linux kernel 3.13.0, int 0x21 starts failing (and then int 0x22, int 0x23 and int 0x24 would also fail).
I was trying to write the shortest example C code to demonstrate the problem, here it is:
/* Based on: https://gist.github.com/zserge/d68683f17c68709818f8baab0ded2d15
* Based on: https://gist.githubusercontent.com/zserge/d68683f17c68709818f8baab0ded2d15/raw/b79033254b092ec9121bb891938b27dd128030d7/kvm-host-simple.c
*
* Compile: gcc -ansi -pedantic -s -O2 -W -Wall -o kvm16 kvm16.c && ./kvm16
*
* Expected correct output (e.g. on Linux 3.16.0 compiled for i386 (i686)):
*
* ...
* info: int 0x4f iret to: ...
* info: success, exiting
*
* Failure output (e.g. on Linux 3.13.0 compiled for amd64 (x86_64)):
*
* info: int 0x20 iret to: cs=0x0070 ip=0x0013
* fatal: KVM internal error suberror=2
*
* // Encounter unexpected simultaneous exceptions.
* #define KVM_INTERNAL_ERROR_SIMUL_EX 2
*/
#define _GNU_SOURCE
#include <fcntl.h>
#include <linux/kvm.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
#define INT_NUM 0x21 /* Also works for INT_NUM == 0x20. */
int main(int argc, char *argv[]) {
int kvm_fd, vm_fd, vcpu_fd;
void *mem;
struct kvm_userspace_memory_region region;
struct kvm_run *run;
struct kvm_regs regs;
struct kvm_sregs sregs;
(void)argc; (void)argv;
if ((kvm_fd = open("/dev/kvm", O_RDWR)) < 0) {
perror("failed to open /dev/kvm");
return 1;
}
if ((vm_fd = ioctl(kvm_fd, KVM_CREATE_VM, 0)) < 0) {
perror("failed to create vm");
return 1;
}
if ((mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0)) == NULL) {
perror("mmap");
return 1;
}
memset(&region, 0, sizeof(region));
region.slot = 0;
region.guest_phys_addr = 0;
region.memory_size = 0x1000;
region.userspace_addr = (uintptr_t)mem;
if (ioctl(vm_fd, KVM_SET_USER_MEMORY_REGION, &region) < 0) {
perror("KVM_SET_USER_MEMORY_REGION");
return 1;
}
{ /* 8086 real mode machine code. */
char *p = (char*)mem + 0x700;
unsigned int_num;
for (int_num = 0; int_num < 0x100; ++int_num) {
*(unsigned short*)((char*)mem + int_num * 4) = int_num; /* Interrupt vector INT_NUM offset := INT_NUM. */
*(unsigned short*)((char*)mem + int_num * 4 + 2) = 0x54; /* Interrupt vector INT_NUM segment := 0x54. */
}
*p++ = (char)0xf4; /* hlt. */
for (int_num = 0x18; int_num < 0x50; ++int_num) {
*p++ = (char)0xcd; /* int int_num. */
*p++ = (char)int_num;
}
*p++ = (char)0xf4;
}
memset((char*)mem + 0x540, '\xf4', 0x100); /* 256 times hlt. Interrupt vectors point here. */
if ((vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0)) < 0) {
perror("KVM_CREATE_VCPU");
return 1;
}
{
int kvm_run_mmap_size = ioctl(kvm_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
if (kvm_run_mmap_size < 0) {
perror("KVM_GET_VCPU_MMAP_SIZE");
return 1;
}
run = (struct kvm_run *)mmap(
NULL, kvm_run_mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpu_fd, 0);
if (run == NULL) {
perror("mmap kvm_run");
return 1;
}
}
memset(&regs, '\0', sizeof(regs));
if (ioctl(vcpu_fd, KVM_GET_SREGS, &sregs) < 0) {
perror("KVM_GET_SREGS");
return 1;
}
{
int fd = open("kvm16.sregs", O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd < 0) {
perror("open");
return 1;
}
if (write(fd, &sregs, sizeof(sregs)) != sizeof(sregs)) {
perror("write");
return 1;
}
if (close(fd) != 0) {
perror("close");
return 1;
}
}
sregs.cs.base = (sregs.cs.selector = 0x70) << 4;
sregs.ds.base = (sregs.ds.selector = sregs.cs.selector) << 4;
sregs.es.base = (sregs.es.selector = sregs.cs.selector) << 4;
sregs.ss.base = (sregs.ss.selector = sregs.cs.selector) << 4;
if (ioctl(vcpu_fd, KVM_GET_REGS, &regs) < 0) {
perror("KVM_GET_REGS");
return 1;
}
regs.rflags = 1 << 1; /* Reserved bit in EFLAGS. Even needed after KVM_GET_REGS. */
regs.rip = 0;
regs.rsp = 0x1000 - 0x700;
if (ioctl(vcpu_fd, KVM_SET_SREGS, &sregs) < 0) {
perror("KVM_SET_SREGS");
return 1;
}
if (ioctl(vcpu_fd, KVM_SET_REGS, &regs) < 0) {
perror("KVM_SET_REGS");
return 1;
}
for (;;) {
int ret = ioctl(vcpu_fd, KVM_RUN, 0);
unsigned short cs, ip;
if (ret < 0) {
perror("KVM_RUN");
return 1;
}
if (ioctl(vcpu_fd, KVM_GET_SREGS, &sregs) < 0) {
perror("KVM_GET_SREGS");
return 1;
}
if (ioctl(vcpu_fd, KVM_GET_REGS, &regs) < 0) {
perror("KVM_GET_REGS");
return 1;
}
cs = sregs.cs.selector;
ip = regs.rip;
if (run->exit_reason == KVM_EXIT_HLT) {
fprintf(stderr, "info: hlt: cs=0x%04x ip=0x%04x\n", cs, ip - 1);
if (cs == 0x70) {
if (ip != 0 + 1) {
fprintf(stderr, "info: success, exiting\n");
return 0; /* EXIT_SUCCESS after the second `hlt' in the code. */
}
} else if (cs == 0x54) { /* Simulate iret. */
const char *csip_ptr = (const char*)mem + ((unsigned short)sregs.ss.selector << 4) + (unsigned short)regs.rsp;
const unsigned short int_ip = ((const unsigned short*)csip_ptr)[0];
const unsigned short int_cs = ((const unsigned short*)csip_ptr)[1];
const unsigned short int_flags = ((const unsigned short*)csip_ptr)[2];
fprintf(stderr, "info: int 0x%02x iret to: cs=0x%04x ip=0x%04x\n", ip - 1, int_cs, int_ip);
sregs.cs.base = (sregs.cs.selector = int_cs) << 4;
regs.rip = int_ip;
if (int_flags & (1 << 9)) regs.rflags |= (1 << 9); /* Set IF back to 1 if it was 1. */
regs.rsp += 6; /* pop ip, pop cs, popfw . */
if (ioctl(vcpu_fd, KVM_SET_SREGS, &sregs) < 0) {
perror("KVM_SET_SREGS");
return 1;
}
if (ioctl(vcpu_fd, KVM_SET_REGS, &regs) < 0) {
perror("KVM_SET_REGS");
return 1;
}
} else {
fprintf(stderr, "fatal: unexpected hlt: cs=0x%04x ip=0x%04x\n", cs, ip - 1);
return 5;
}
} else if (run->exit_reason == KVM_EXIT_INTERNAL_ERROR) {
fprintf(stderr, "fatal: KVM internal error suberror=%d\n", (unsigned)run->internal.suberror);
return 4;
} else {
fprintf(stderr, "fatal: unexpected KVM exit: exit_reason=%d cs=0x%04x ip=0x%04x\n", run->exit_reason, cs, ip);
return 2;
}
}
}

Using perf_event_open() to get sample address ,however the addr=0

I tried to use perf_event_open() to track all the store instructions to get their access address. I found only when I set attr.precise_ip > 0, I can get the non-zero address. But when I ran the same process on vm instead of host, the error massage was "Operation not supported", I can fix this problem by setting precise_ip = 0 on vm, but now I only get bunch of addresses equal to zero. I don't understand why precise_ip is related to the sample addrress which is not pointed out on document, and I also don't understand why I can't set precise_ip = 1 on vm while I can do it on host. Is there anybody can help me??
FYI: I use - cpu host option when I start vm using qemu-system-x86_64
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/fcntl.h>
#include <sys/syscall.h>
#include <linux/perf_event.h>
#define PERF_PAGES (1 + (1 << 16))
struct perf_sample {
struct perf_event_header header;
__u64 ip;
__u32 pid, tid; /* if PERF_SAMPLE_TID */
__u64 addr; /* if PERF_SAMPLE_ADDR */
__u64 weight; /* if PERF_SAMPLE_WEIGHT */
/* __u64 data_src; /\* if PERF_SAMPLE_DATA_SRC *\/ */
__u64 phy_addr;
};
int perf_event_open(struct perf_event_attr *attr,pid_t pid,int cpu,int group_fd,unsigned long flags)
{
return syscall(__NR_perf_event_open,attr,pid,cpu,group_fd,flags);
}
void workload()
{
int i,c=0;
for(i=0;i<100000000;i++)
{
c+=i*i;
c-=i*100;
c+=i*i*i/100;
}
}
int startup()
{
struct perf_event_attr attr;
memset(&attr,0,sizeof(struct perf_event_attr));
attr.type = PERF_TYPE_RAW;
attr.size = sizeof(struct perf_event_attr);
attr.config = 0x82d0;
attr.config1 = 0;
attr.sample_period = 1000;
attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_WEIGHT | PERF_SAMPLE_ADDR | PERF_SAMPLE_PHYS_ADDR ;
attr.disabled = 0;
//attr.inherit = 1;
attr.exclude_kernel = 1;
attr.exclude_hv = 1;
attr.exclude_callchain_kernel = 1;
attr.exclude_callchain_user = 1;
attr.precise_ip = 1; // when i set attr.precise_ip = 0 , all the addr = 0;
int fd=perf_event_open(&attr,0,-1,-1,0);
if(fd<0)
{
perror("Cannot open perf fd!");
return -1;
}
return fd;
}
void scan_thread(struct perf_event_mmap_page *p)
{
char *pbuf = (char *)p + p->data_offset;
__sync_synchronize();
printf("%d,\n", p->data_size);
if(p->data_head == p->data_tail) {
return;
}
struct perf_event_header *ph = (void *)(pbuf + (p->data_tail % p->data_size));
struct perf_sample* ps;
switch(ph->type) {
case PERF_RECORD_SAMPLE:
ps = (struct perf_sample*)ph;
// assert(ps != NULL);
if(ps == NULL)
{
printf("null\n");
}
if(ps!= NULL && ps->addr != 0) {
printf("ip %lx\n", ps->ip);
printf("tid %d\n", ps->tid);
printf("addr: %lx \n", ps->addr);
}
//printf("addr, %lx\n", ps->addr);
//printf("phy addr, %lx\n", ps->phy_addr);
break;
default:
printf("type %d\n", ph->type);
break;
}
}
int main()
{
int fd = startup();
size_t mmap_size = sysconf(_SC_PAGESIZE) * PERF_PAGES;
struct perf_event_mmap_page *p = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// start to perf
ioctl(fd,PERF_EVENT_IOC_ENABLE,0);
int a= 0;
while(1)
{
// uint64_t instructions;
// read(fd,&instructions,sizeof(instructions));
// printf("instructions=%ld\n",instructions);
// sleep(1);
workload();
scan_thread(p);
sleep(1);
}
}

How to generate incremental data value in DPDK

Code image
Hello DPDK Users,
I was trying to generate the incremental data value of UDP packets via DPDK.
But when I am transmitting it, I verified the same frames in Wireshark.
The data part of packets is changing illogically.
No sequence can be seen in data.
It is optimized the data value which I was wrote. The last value i tried to write was there in all the bytes of payload, not as expected in incremental order.
Can anyone help me, why is this occurring and what could be the easiest way to generate incremental DPDK packets?
The Code is given in the image file above.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include<assert.h>
uint64_t temp1;
uint64_t temp2;
int temp3;
int test_type;
double sec;
time_t start_t,end_t;
double diff_t;
#include<time.h>
#include<signal.h>
#include<linux/kernel.h>
#include <rte_memory.h>
#include <rte_launch.h>
#include <rte_eal.h>
#include <rte_per_lcore.h>
#include <rte_lcore.h>
#include <rte_ethdev.h>
#include <rte_udp.h>
#include <rte_tcp.h>
#include <rte_ip.h>
#include <rte_arp.h>
#include <rte_icmp.h>
#include <rte_cycles.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>
#define RX_RING_SIZE 2028
#define TX_RING_SIZE 2048
#define NUM_MBUFS 8191
#define MBUF_CACHE_SIZE 250
#define BURST_SIZE 32
#define UDP_SRC_PORT 6666
#define UDP_DST_PORT 6666
#define TCP_SRC_PORT 6666
#define TCP_DST_PORT 6666
#define IP_DEFTTL 64
#define IP_VERSION 0x40
#define IP_HDRLEN 0x05
#define IP_VHL_DEF (IP_VERSION | IP_HDRLEN)
#define TX_PACKET_LENGTH 64
#define ETHER_MAX_LEN 1518
#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
#define RTE_BE_TO_CPU_16(be_16_v) (be_16_v)
#define RTE_CPU_TO_BE_16(cpu_16_v) (cpu_16_v)
#else
#define RTE_BE_TO_CPU_16(be_16_v) \
(uint16_t) ((((be_16_v) & 0xFF) << 8) | ((be_16_v) >> 8))
#define RTE_CPU_TO_BE_16(cpu_16_v) \
(uint16_t) ((((cpu_16_v) & 0xFF) << 8) | ((cpu_16_v) >> 8))
#endif
#define rte_ctrlmbuf_data(m) ((char *)((m)->buf_addr)+(m)->data_off)
// convert a quad-dot IP string to uint32_t IP address
uint32_t string_to_ip(char *s) {
unsigned char a[4];
int rc = sscanf(s, "%d.%d.%d.%d",a+0,a+1,a+2,a+3);
if(rc != 4){
fprintf(stderr, "bad source IP address format. Use like: -s 198.19.111.179\n");
exit(1);
}
return
(uint32_t)(a[0]) << 24 |
(uint32_t)(a[1]) << 16 |
(uint32_t)(a[2]) << 8 |
(uint32_t)(a[3]);
}
// convert six colon separated hex bytes string to uint64_t Ethernet MAC address
uint64_t string_to_mac(char *s) {
unsigned char a[6];
int rc = sscanf(s, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
a + 0, a + 1, a + 2, a + 3, a + 4, a + 5);
if(rc !=6 ){
fprintf(stderr, "bad MAC address format. Use like: -m 0a:38:ca:f6:f3:20\n");
exit(1);
}
return
(uint64_t)(a[0]) << 40 |
(uint64_t)(a[1]) << 32 |
(uint64_t)(a[2]) << 24 |
(uint64_t)(a[3]) << 16 |
(uint64_t)(a[4]) << 8 |
(uint64_t)(a[5]);
}
uint64_t DST_MAC;
uint32_t IP_SRC_ADDR,IP_DST_ADDR;
static const struct rte_eth_conf port_conf_default = {
.rxmode = { .max_rx_pkt_len = RTE_ETHER_MAX_LEN }
};
static struct rte_ipv4_hdr pkt_ip_hdr;
static struct rte_udp_hdr pkt_udp_hdr;
struct rte_ether_addr my_addr;
struct rte_mempool *mbuf_pool;
struct rte_data_hdr pkt_data_hdr;
static void setup_pkt_udp_ip_headers(struct rte_ipv4_hdr *ip_hdr,
struct rte_udp_hdr *pudp_hdr,
uint16_t pkt_data_len)
{
uint16_t *ptr16;
uint32_t ip_cksum;
uint16_t pkt_len;
int sizeof_=sizeof(struct rte_udp_hdr);
int sizeof__=sizeof(struct rte_ipv4_hdr);
//initialize udp headers
pkt_len = (uint16_t) (pkt_data_len + sizeof_);
pudp_hdr->src_port = rte_cpu_to_be_16(UDP_SRC_PORT);
pudp_hdr->dst_port = rte_cpu_to_be_16(UDP_DST_PORT);
pudp_hdr->dgram_len = RTE_CPU_TO_BE_16(pkt_len);
pudp_hdr->dgram_cksum = 32; // No udp checksum.
//Initialize IP header.
pkt_len = (uint16_t) (pkt_len + sizeof__);
ip_hdr->version_ihl = IP_VHL_DEF;
ip_hdr->type_of_service = 0;
ip_hdr->fragment_offset = 0;
ip_hdr->time_to_live = IP_DEFTTL;
ip_hdr->next_proto_id = IPPROTO_UDP;
ip_hdr->packet_id = 0;
ip_hdr->total_length = RTE_CPU_TO_BE_16(pkt_len);
ip_hdr->src_addr = rte_cpu_to_be_32(IP_SRC_ADDR);
ip_hdr->dst_addr = rte_cpu_to_be_32(IP_DST_ADDR);
//Compute IP header checksum.
ptr16 = (unaligned_uint16_t*) ip_hdr;
ip_cksum = 0;
ip_cksum += ptr16[0]; ip_cksum += ptr16[1];
ip_cksum += ptr16[2]; ip_cksum += ptr16[3];
ip_cksum += ptr16[4];
ip_cksum += ptr16[6]; ip_cksum += ptr16[7];
ip_cksum += ptr16[8]; ip_cksum += ptr16[9];
//Reduce 32 bit checksum to 16 bits and complement it.
ip_cksum = ((ip_cksum & 0xFFFF0000) >> 16) +
(ip_cksum & 0x0000FFFF);
if (ip_cksum > 65535)
ip_cksum -= 65535;
ip_cksum = (~ip_cksum) & 0x0000FFFF;
if (ip_cksum == 0)
ip_cksum = 0xFFFF;
ip_hdr->hdr_checksum = (uint16_t) ip_cksum;
}
union {
uint64_t as_int;
struct rte_ether_addr as_addr;
} dst_eth_addr;
static void packetsend_withSequence()
{
int counter=1;
int pkt_drop_counter=0;
struct rte_ether_hdr eth_hdr;
struct rte_mbuf *pkt=NULL;
struct rte_mbuf *pkts_burst[1];
struct rte_mbuf *m;
char *data;
char temppacketdata[100];
while(1){
pkt = rte_pktmbuf_alloc(mbuf_pool);
if(pkt == NULL) {printf("trouble at rte_mbuf_raw_alloc\n");}
data = rte_pktmbuf_append(pkt, TX_PACKET_LENGTH);
if(data == NULL ) {printf("trouble at data alloc\n");}
// set up addresses
printf("\n rte_pktmbuf_pkt_len is %d", rte_pktmbuf_pkt_len(pkt));
dst_eth_addr.as_int=rte_cpu_to_be_64(DST_MAC);
rte_ether_addr_copy(&dst_eth_addr,&eth_hdr.d_addr);
rte_ether_addr_copy(&my_addr, &eth_hdr.s_addr);
eth_hdr.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
memset(temppacketdata,0x0,sizeof(temppacketdata));
memcpy(temppacketdata, &eth_hdr,(size_t)sizeof(eth_hdr)); //copy eth header
memcpy(temppacketdata+(size_t)sizeof(eth_hdr), &pkt_ip_hdr,(size_t)sizeof(pkt_ip_hdr)); //copy IP header
memcpy(temppacketdata+(size_t)sizeof(eth_hdr)+(size_t)sizeof(pkt_ip_hdr), &pkt_udp_hdr,(size_t)sizeof(pkt_udp_hdr)); //copy UDP header
memcpy(temppacketdata+(size_t)sizeof(eth_hdr)+(size_t)sizeof(pkt_ip_hdr)+(size_t)sizeof(pkt_udp_hdr), &counter,(size_t)sizeof(counter)); //copy int data
memcpy(data,temppacketdata,rte_pktmbuf_pkt_len(pkt));
pkts_burst[0] = pkt;
const uint16_t nb_tx = rte_eth_tx_burst(0, 0, pkts_burst,1);
if (unlikely(nb_tx < 1))
{
pkt_drop_counter++;
rte_pktmbuf_free(pkt); // This frees chained segs
}
else{
counter++;
printf("%d",nb_tx);
}
if(counter > 1000)
break;
}
printf(" pkt_drop_counter = %d counter =%d",pkt_drop_counter,counter);
}
// Initialize Port
static inline int
port_init(uint16_t port, struct rte_mempool *mbuf_pool)
{
struct rte_eth_conf port_conf = port_conf_default;
const uint16_t rx_rings = 1, tx_rings = 1;
uint16_t nb_rxd = RX_RING_SIZE;
uint16_t nb_txd = TX_RING_SIZE;
int retval;
uint16_t q;
struct rte_eth_dev_info dev_info;
struct rte_eth_txconf txconf;
if (!rte_eth_dev_is_valid_port(port))
return -1;
rte_eth_dev_info_get(port, &dev_info);
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
port_conf.txmode.offloads |=
DEV_TX_OFFLOAD_MBUF_FAST_FREE;
/* Configure the Ethernet device. */
retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
if (retval != 0)
return retval;
retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
if (retval != 0)
return retval;
txconf = dev_info.default_txconf;
txconf.offloads = port_conf.txmode.offloads;
//Allocate and set up 1 TX queue
for (q = 0; q < tx_rings; q++) {
retval = rte_eth_tx_queue_setup(port, q, nb_txd,
rte_eth_dev_socket_id(port), &txconf);
if (retval < 0)
return retval;
}
/* Allocate and set up 1 RX queue per Ethernet port. */
for (q = 0; q < rx_rings; q++) {
retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
rte_eth_dev_socket_id(port), NULL, mbuf_pool);
if (retval < 0)
return retval;
}
/* Start the Ethernet port. */
retval = rte_eth_dev_start(port);
if (retval < 0)
return retval;
/* get the port MAC address. */
rte_eth_macaddr_get(port, &my_addr);
printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
" %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
port,
my_addr.addr_bytes[0], my_addr.addr_bytes[1],
my_addr.addr_bytes[2], my_addr.addr_bytes[3],
my_addr.addr_bytes[4], my_addr.addr_bytes[5]);
return 0;
}
int main(int argc, char **argv)
{
int ret,c;
uint16_t pkt_data_len;
int mac_flag=0,ip_src_flag=0,ip_dst_flag=0;
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_panic("Cannot init EAL\n");
argc -= ret;
argv += ret;
while ((c = getopt(argc, argv, "m:s:d:h")) != -1)
switch(c) {
case 'm':
// note, not quite sure why last two bytes are zero, but that is how DPDK likes it
DST_MAC=0ULL;
DST_MAC=string_to_mac(optarg)<<16;
mac_flag=1;
break;
case 's':
IP_SRC_ADDR=string_to_ip(optarg);
ip_src_flag=1;
break;
case 'd':
IP_DST_ADDR=string_to_ip(optarg);
ip_dst_flag=1;
break;
case 'h':
printf("usage -- -m [dst MAC] -s [src IP] -d [dst IP]\n");
exit(0);
break;
}
if(mac_flag==0) {
fprintf(stderr, "missing -m for destination MAC adress\n");
exit(1);
}
if(ip_src_flag==0) {
fprintf(stderr, "missing -s for IP source adress\n");
exit(1);
}
if(ip_dst_flag==0) {
fprintf(stderr, "missing -d for IP destination adress\n");
exit(1);
}
/* Creates a new mempool in memory to hold the mbufs. */
mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS,
MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (mbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
// initialize port 0
if (port_init(0,mbuf_pool) != 0)
rte_exit(EXIT_FAILURE, "Cannot init port 0\n");
/* Initialize all ports. */
if (port_init(1, mbuf_pool) != 0)
rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16 "\n",
1);
pkt_data_len = (uint16_t) (TX_PACKET_LENGTH - (sizeof(struct rte_ether_hdr) +
sizeof(struct rte_ipv4_hdr) +
sizeof(struct rte_udp_hdr)));
setup_pkt_udp_ip_headers(&pkt_ip_hdr, &pkt_udp_hdr, pkt_data_len);
packetsend_withSequence();
// send_packet();
return(0);
}

unable to interface beaglebonegreen with mcp3008 using SPI

I am unable to interface mcp 3008 with beaglebone green.trying to set communication in mode 0(CPOL =0 CPHA=0),the built in frequency in dts is set to 1Mhz.
things I have tried
1.enable device tree BB-SPI0-MCP3008-00A0.dts
on execution of
ls -al /dev/spidev1.*
I got
crw-rw---- 1 root spi 153, 0 Oct 7 16:40 /dev/spidev1.1
2.on execution of
cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pingroups
group: pinmux_bb_spi0_pins pin 84 (PIN84) pin 85 (PIN85) pin 86 (PIN86) pin 87 (PIN87)
My reference code is as follow
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#define ARRAY_SIZE(array) sizeof(array) / sizeof(array[0])
static const char *DEVICE = "/dev/spidev1.1";
static uint8_t MODE = SPI_MODE_0;
static uint8_t BITS = 8;
static uint32_t CLOCK = 1000000;
static uint16_t DELAY = 5;
/* * Ensure all settings are correct for the ADC */
static int prepare(int fd)
{
if (ioctl(fd, SPI_IOC_WR_MODE, &MODE) == -1)
{
perror("Can't set MODE"); return -1;
}
if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &BITS) == -1)
{
perror("Can't set number of BITS");
return -1;
}
if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &CLOCK) == -1)
{
perror("Can't set write CLOCK");
return -1;
}
if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &CLOCK) == -1)
{
perror("Can't set read CLOCK"); return -1;
}
return 0;
}
/* * (SGL/DIF = 0, D2=D1=D0=0) */
uint8_t control_bits_differential(uint8_t channel)
{
return (channel & 7) << 4;
}
/* * (SGL/DIF = 1, D2=D1=D0=0) */
uint8_t control_bits(uint8_t channel)
{
return 0x8 | control_bits_differential(channel);
}
/* * Given a prep'd descriptor, and an ADC channel, fetch the * raw ADC
value for the given channel. */
int readadc(int fd, uint8_t channel)
{
uint8_t tx[] = {1, control_bits(channel), 0
};
uint8_t rx[3]={0,0,0};
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = DELAY,
.speed_hz = CLOCK,
.bits_per_word = BITS, };
if (ioctl(fd, SPI_IOC_MESSAGE(1), &tr) == 1)
{
perror("IO Error");
abort();
}
return ((rx[1] << 8) & 0x300) | (rx[2] & 0xFF);
}
int main(int argc, char **argv)
{
int fd = open(DEVICE, O_RDWR);
if (fd <= 0)
{
printf("Device %s not found\n", DEVICE);
return -1;
}
if (prepare(fd) == -1)
{ return -1; }
uint8_t i,radc=0;
for(i = 0;i < 8;i++)
{ printf("Channel %d: %d\n", i + 1, readadc(fd, i)); }
close(fd);
return 0;
}
after executing this code I am getting 1023 count for any applied voltage,where I am expecting count 0 for 0 input voltage and so on .
Can anybody please help me? can you tell me where I am doing wrong?what are the other things I have to consider while using SPI on beaglebone?any kind of help will be greatly appreciated!
solved it as suggested from other forum it was hardware related thing.I have to put 0.1uf capacitor between vcc and gnd,where analog ground and digital ground were common.

Unable to read PCI BAR from kernel mode

I have written some code to probe registers of an AMD Vega from userspace using a mmap of the /sys resource. This is working and I am able to read the register values without any problems. However when I implement the kernel mode version of this, all reads return 0xffffffff. I feel like I am missing something simple as the userspace code is returning expected values, where the kernel code fails to read the registers.
Here is the working userspace code:
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <stdint.h>
#define RES_PATH "/sys/devices/pci0000:40/0000:40:01.3/0000:42:00.0/0000:43:00.0/0000:44:00.0/resource5"
#define RES_SIZE (512*1024)
#define MP0_BASE 0x16000
#define mmMP0_SMN_C2PMSG_33 ((MP0_BASE + 0x61) * 4)
#define mmMP0_SMN_C2PMSG_64 ((MP0_BASE + 0x80) * 4)
#define mmMP0_SMN_C2PMSG_81 ((MP0_BASE + 0x91) * 4)
void * map;
uint32_t _preadl(const char * name, uint32_t reg)
{
uint32_t val = *(uint32_t*)(map + reg);
printf("readl %20s (0x%08x / 0x%08x) = 0x%08x\n", name, reg / 4, reg, val);
return val;
}
#define preadl(x) _preadl(#x, x)
int main(int argc, char * argv[])
{
int fd = open(RES_PATH, O_RDWR | O_SYNC, 0);
map = mmap(NULL, RES_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("mmap = %p\n", map);
preadl(mmMP0_SMN_C2PMSG_33);
preadl(mmMP0_SMN_C2PMSG_64);
preadl(mmMP0_SMN_C2PMSG_81);
return 0;
}
And here is the non working kernel code:
static int reset_amdgpu_vega(struct pci_dev *dev, int probe)
{
#define MP0_BASE 0x16000
#define mmMP0_SMN_C2PMSG_33 ((MP0_BASE + 0x61) * 4)
#define mmMP0_SMN_C2PMSG_64 ((MP0_BASE + 0x80) * 4)
#define mmMP0_SMN_C2PMSG_81 ((MP0_BASE + 0x91) * 4)
resource_size_t mmio_base, mmio_size;
void __iomem *mmio;
int ret;
int i;
uint32_t val;
if (probe)
return 0;
mmio_base = pci_resource_start(dev, 5);
mmio_size = pci_resource_len(dev, 5);
mmio = pci_iomap(dev, 5, 0);
if (mmio == NULL) {
printk(KERN_ERR
"[reset_amdgpu_vega] failed to map the resource\n");
ret = -ENOMEM;
goto out;
}
printk(KERN_INFO "mmio: %llx %llx %lx\n",
mmio_base,
mmio_size,
(uintptr_t)mmio);
printk(KERN_INFO "regs: %08x %08x %08x\n",
mmMP0_SMN_C2PMSG_33,
mmMP0_SMN_C2PMSG_64,
mmMP0_SMN_C2PMSG_81);
printk(KERN_INFO "vals: %08x %08x %08x\n",
ioread32(mmio + mmMP0_SMN_C2PMSG_33),
ioread32(mmio + mmMP0_SMN_C2PMSG_64),
ioread32(mmio + mmMP0_SMN_C2PMSG_81));
pci_iounmap(dev, mmio);
ret = 0;
out:
return ret;
}
The problem was that before the pci reset quirk is called, the kernel turns off the PCI_COMMAND_MEMORY flag on the COMMAND register. By doing so the device is no longer readable. The solution is to re-enable the flag first:
pci_read_config_word(dev, PCI_COMMAND, &cfg);
cfg |= PCI_COMMAND_MEMORY;
pci_write_config_word(dev, PCI_COMMAND, cfg);

Resources