summaryrefslogtreecommitdiff
path: root/fuzz/pchg_fuzz.c
blob: 4ef5f28b748ead6490831cc73d7738fbc08a6705 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* Copyright 2021 The ChromiumOS Authors
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * Test peripheral device charger module.
 */

#include "common.h"
#include "compile_time_macros.h"
#include "driver/nfc/ctn730.h"
#include "peripheral_charger.h"
#include "task.h"
#include "test_util.h"
#include "timer.h"
#include "util.h"

#include <pthread.h>
#include <stdlib.h>
#include <string.h>

#define TASK_EVENT_FUZZ TASK_EVENT_CUSTOM_BIT(0)

extern struct pchg_drv ctn730_drv;
struct pchg pchgs[] = {
	[0] = {
		.cfg = &(const struct pchg_config) {
			.drv = &ctn730_drv,
			.i2c_port = I2C_PORT_WLC,
			.irq_pin = GPIO_WLC_IRQ_CONN,
			.full_percent = 96,
			.block_size = 128,
		},
		.events = QUEUE_NULL(PCHG_EVENT_QUEUE_SIZE, enum pchg_event),
	},
};
const int pchg_count = ARRAY_SIZE(pchgs);

static pthread_cond_t done_cond;
static pthread_mutex_t lock;

#define MAX_MESSAGES 8
#define MAX_MESSAGE_SIZE             \
	(sizeof(struct ctn730_msg) + \
	 member_size(struct ctn730_msg, length) * 256)
static uint8_t input[MAX_MESSAGE_SIZE * MAX_MESSAGES];
static uint8_t *head, *tail;
static bool data_available;

int pchg_i2c_xfer(int port, uint16_t addr_flags, const uint8_t *out,
		  int out_size, uint8_t *in, int in_size, int flags)
{
	if (port != I2C_PORT_WLC || addr_flags != CTN730_I2C_ADDR)
		return EC_ERROR_INVAL;

	if (in == NULL || in_size == 0)
		return EC_SUCCESS;

	if (head + in_size >= tail) {
		data_available = false;
		return EC_ERROR_OVERFLOW;
	}

	memcpy(in, head, in_size);
	head += in_size;

	return EC_SUCCESS;
}
DECLARE_TEST_I2C_XFER(pchg_i2c_xfer);

/*
 * Task for generating IRQs. The task priority is lower than the PCHG task so
 * that it can yield the CPU to the PCHG task.
 */
void irq_task(int argc, char **argv)
{
	ccprints("%s task started", __func__);
	wait_for_task_started();

	while (1) {
		int i = 0;

		task_wait_event_mask(TASK_EVENT_FUZZ, -1);
		test_chipset_on();

		while (data_available && i++ < MAX_MESSAGES)
			pchg_irq(pchgs[0].cfg->irq_pin);

		test_chipset_off();

		pthread_mutex_lock(&lock);
		pthread_cond_signal(&done_cond);
		pthread_mutex_unlock(&lock);
	}
}

void run_test(int argc, const char **argv)
{
	ccprints("Fuzzing task started");
	task_wait_event(-1);
}

int test_fuzz_one_input(const uint8_t *data, unsigned int size)
{
	/* We're not interested in too small or too large input. */
	if (size < sizeof(struct ctn730_msg) || sizeof(input) < size)
		return 0;

	pthread_mutex_init(&lock, NULL);
	pthread_cond_init(&done_cond, NULL);

	head = input;
	tail = input + size;
	memcpy(input, data, size);
	data_available = true;

	task_set_event(TASK_ID_IRQ, TASK_EVENT_FUZZ);

	pthread_mutex_lock(&lock);
	pthread_cond_wait(&done_cond, &lock);
	pthread_mutex_unlock(&lock);

	return 0;
}