drivers: Perform a runtime check if a driver is capable of an operation
Driver APIs might not implement all operations, making it possible for a user thread to get the kernel to execute a function at 0x00000000. Perform runtime checks in all the driver handlers, checking if they're capable of performing the requested operation. Fixes #6907. Signed-off-by: Leandro Pereira <leandro.pereira@intel.com>
This commit is contained in:
parent
e7ded11a2e
commit
c200367b68
|
@ -364,6 +364,19 @@ add_custom_command(OUTPUT include/generated/syscall_dispatch.c ${syscall_list_h}
|
|||
DEPENDS ${syscalls_json}
|
||||
)
|
||||
|
||||
set(DRV_VALIDATION ${PROJECT_BINARY_DIR}/include/generated/driver-validation.h)
|
||||
add_custom_command(
|
||||
OUTPUT ${DRV_VALIDATION}
|
||||
COMMAND
|
||||
${PYTHON_EXECUTABLE}
|
||||
${ZEPHYR_BASE}/scripts/gen_kobject_list.py
|
||||
--validation-output ${DRV_VALIDATION}
|
||||
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
add_custom_target(driver_validation_h_target DEPENDS ${DRV_VALIDATION})
|
||||
|
||||
|
||||
# Generate offsets.c.obj from offsets.c
|
||||
# Generate offsets.h from offsets.c.obj
|
||||
|
||||
|
@ -376,6 +389,7 @@ target_link_libraries(offsets zephyr_interface)
|
|||
add_dependencies( offsets
|
||||
syscall_list_h_target
|
||||
syscall_macros_h_target
|
||||
driver_validation_h_target
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
|
@ -782,7 +796,7 @@ if(CONFIG_USERSPACE)
|
|||
${PYTHON_EXECUTABLE}
|
||||
${GEN_KOBJ_LIST}
|
||||
--kernel $<TARGET_FILE:zephyr_prebuilt>
|
||||
--output ${OBJ_LIST}
|
||||
--gperf-output ${OBJ_LIST}
|
||||
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
|
||||
DEPENDS zephyr_prebuilt
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
|
|
|
@ -292,6 +292,9 @@ Several macros exist to validate arguments:
|
|||
a message parameter, instead printing the expression tested if it
|
||||
fails. The latter should only be used for the most obvious of tests.
|
||||
|
||||
* :c:macro:`_SYSCALL_DRIVER_OP()` checks at runtime if a driver
|
||||
instance is capable of performing a particular operation.
|
||||
|
||||
If any check fails, a kernel oops will be triggered which will kill the
|
||||
calling thread. This is done instead of returning some error condition to
|
||||
keep the APIs the same when calling from supervisor mode.
|
||||
|
|
|
@ -7,8 +7,19 @@
|
|||
#include <adc.h>
|
||||
#include <syscall_handler.h>
|
||||
|
||||
_SYSCALL_HANDLER1_SIMPLE_VOID(adc_enable, K_OBJ_DRIVER_ADC, struct device *);
|
||||
_SYSCALL_HANDLER1_SIMPLE_VOID(adc_disable, K_OBJ_DRIVER_ADC, struct device *);
|
||||
_SYSCALL_HANDLER(adc_enable, dev)
|
||||
{
|
||||
_SYSCALL_DRIVER_ADC(dev, enable);
|
||||
_impl_adc_enable((struct device *)dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(adc_disable, dev)
|
||||
{
|
||||
_SYSCALL_DRIVER_ADC(dev, disable);
|
||||
_impl_adc_disable((struct device *)dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(adc_read, dev, seq_table_p)
|
||||
{
|
||||
|
@ -16,7 +27,7 @@ _SYSCALL_HANDLER(adc_read, dev, seq_table_p)
|
|||
struct adc_seq_table *seq_table = (struct adc_seq_table *)seq_table_p;
|
||||
int i;
|
||||
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_ADC);
|
||||
_SYSCALL_DRIVER_ADC(dev, read);
|
||||
_SYSCALL_MEMORY_READ(seq_table, sizeof(struct adc_seq_table));
|
||||
_SYSCALL_MEMORY_ARRAY_READ(seq_table->entries, seq_table->num_entries,
|
||||
sizeof(struct adc_seq_entry));
|
||||
|
|
|
@ -9,9 +9,12 @@
|
|||
|
||||
_SYSCALL_HANDLER(aio_cmp_disable, dev, index)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_AIO);
|
||||
_SYSCALL_DRIVER_AIO_CMP(dev, disable);
|
||||
return _impl_aio_cmp_disable((struct device *)dev, index);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER1_SIMPLE(aio_cmp_get_pending_int, K_OBJ_DRIVER_AIO,
|
||||
struct device *);
|
||||
_SYSCALL_HANDLER(aio_cmp_get_pending_int, dev)
|
||||
{
|
||||
_SYSCALL_DRIVER_AIO_CMP(dev, get_pending_int);
|
||||
return _impl_aio_get_pending_int((struct device *)dev, index);
|
||||
}
|
||||
|
|
|
@ -11,9 +11,13 @@
|
|||
* instance and return an integral value
|
||||
*/
|
||||
#define COUNTER_HANDLER(name) \
|
||||
_SYSCALL_HANDLER1_SIMPLE(name, K_OBJ_DRIVER_COUNTER, struct device *)
|
||||
_SYSCALL_HANDLER(counter_ ## name, dev) \
|
||||
{ \
|
||||
_SYSCALL_DRIVER_COUNTER(dev, name); \
|
||||
return _impl_counter_ ## name((struct device *)dev); \
|
||||
}
|
||||
|
||||
COUNTER_HANDLER(counter_get_pending_int);
|
||||
COUNTER_HANDLER(counter_read);
|
||||
COUNTER_HANDLER(counter_stop);
|
||||
COUNTER_HANDLER(counter_start);
|
||||
COUNTER_HANDLER(get_pending_int)
|
||||
COUNTER_HANDLER(read)
|
||||
COUNTER_HANDLER(stop)
|
||||
COUNTER_HANDLER(start)
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
|
||||
_SYSCALL_HANDLER(dma_start, dev, channel)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_DMA);
|
||||
_SYSCALL_DRIVER_DMA(dev, start);
|
||||
return _impl_dma_start((struct device *)dev, channel);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(dma_stop, dev, channel)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_DMA);
|
||||
_SYSCALL_DRIVER_DMA(dev, stop);
|
||||
return _impl_dma_stop((struct device *)dev, channel);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
_SYSCALL_HANDLER(entropy_get_entropy, dev, buffer, len)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_ENTROPY);
|
||||
_SYSCALL_DRIVER_ENTROPY(dev, get_entropy);
|
||||
_SYSCALL_MEMORY_WRITE(buffer, len);
|
||||
return _impl_entropy_get_entropy((struct device *)dev, (u8_t *)buffer,
|
||||
len);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
_SYSCALL_HANDLER(flash_read, dev, offset, data, len)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH);
|
||||
_SYSCALL_DRIVER_FLASH(dev, read);
|
||||
_SYSCALL_MEMORY_WRITE(data, len);
|
||||
return _impl_flash_read((struct device *)dev, offset, (void *)data,
|
||||
len);
|
||||
|
@ -17,7 +17,7 @@ _SYSCALL_HANDLER(flash_read, dev, offset, data, len)
|
|||
|
||||
_SYSCALL_HANDLER(flash_write, dev, offset, data, len)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH);
|
||||
_SYSCALL_DRIVER_FLASH(dev, write);
|
||||
_SYSCALL_MEMORY_READ(data, len);
|
||||
return _impl_flash_write((struct device *)dev, offset,
|
||||
(const void *)data, len);
|
||||
|
@ -25,7 +25,7 @@ _SYSCALL_HANDLER(flash_write, dev, offset, data, len)
|
|||
|
||||
_SYSCALL_HANDLER(flash_write_protection_set, dev, enable)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH);
|
||||
_SYSCALL_DRIVER_FLASH(dev, write_protection);
|
||||
return _impl_flash_write_protection_set((struct device *)dev, enable);
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ _SYSCALL_HANDLER1_SIMPLE(flash_get_write_block_size, K_OBJ_DRIVER_FLASH,
|
|||
#ifdef CONFIG_FLASH_PAGE_LAYOUT
|
||||
_SYSCALL_HANDLER(flash_get_page_info_by_offs, dev, offs, info)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH);
|
||||
_SYSCALL_DRIVER_FLASH(dev, page_layout);
|
||||
_SYSCALL_MEMORY_WRITE(info, sizeof(struct flash_pages_info));
|
||||
return _impl_flash_get_page_info_by_offs((struct device *)dev, offs,
|
||||
(struct flash_pages_info *)info);
|
||||
|
@ -43,12 +43,15 @@ _SYSCALL_HANDLER(flash_get_page_info_by_offs, dev, offs, info)
|
|||
|
||||
_SYSCALL_HANDLER(flash_get_page_info_by_idx, dev, idx, info)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH);
|
||||
_SYSCALL_DRIVER_FLASH(dev, page_layout);
|
||||
_SYSCALL_MEMORY_WRITE(info, sizeof(struct flash_pages_info));
|
||||
return _impl_flash_get_page_info_by_idx((struct device *)dev, idx,
|
||||
(struct flash_pages_info *)info);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER1_SIMPLE(flash_get_page_count, K_OBJ_DRIVER_FLASH,
|
||||
struct device *);
|
||||
_SYSCALL_HANDLER(flash_get_page_count, dev)
|
||||
{
|
||||
_SYSCALL_DRIVER_FLASH(dev, page_layout);
|
||||
return _impl_flash_get_page_count((struct device *)dev);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -9,19 +9,19 @@
|
|||
|
||||
_SYSCALL_HANDLER(gpio_config, port, access_op, pin, flags)
|
||||
{
|
||||
_SYSCALL_OBJ(port, K_OBJ_DRIVER_GPIO);
|
||||
_SYSCALL_DRIVER_GPIO(port, config);
|
||||
return _impl_gpio_config((struct device *)port, access_op, pin, flags);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(gpio_write, port, access_op, pin, value)
|
||||
{
|
||||
_SYSCALL_OBJ(port, K_OBJ_DRIVER_GPIO);
|
||||
_SYSCALL_DRIVER_GPIO(port, write);
|
||||
return _impl_gpio_write((struct device *)port, access_op, pin, value);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(gpio_read, port, access_op, pin, value)
|
||||
{
|
||||
_SYSCALL_OBJ(port, K_OBJ_DRIVER_GPIO);
|
||||
_SYSCALL_DRIVER_GPIO(port, read);
|
||||
_SYSCALL_MEMORY_WRITE(value, sizeof(u32_t));
|
||||
return _impl_gpio_read((struct device *)port, access_op, pin,
|
||||
(u32_t *)value);
|
||||
|
@ -29,17 +29,20 @@ _SYSCALL_HANDLER(gpio_read, port, access_op, pin, value)
|
|||
|
||||
_SYSCALL_HANDLER(gpio_enable_callback, port, access_op, pin)
|
||||
{
|
||||
_SYSCALL_OBJ(port, K_OBJ_DRIVER_GPIO);
|
||||
_SYSCALL_DRIVER_GPIO(port, enable_callback);
|
||||
return _impl_gpio_enable_callback((struct device *)port, access_op,
|
||||
pin);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(gpio_disable_callback, port, access_op, pin)
|
||||
{
|
||||
_SYSCALL_OBJ(port, K_OBJ_DRIVER_GPIO);
|
||||
_SYSCALL_DRIVER_GPIO(port, disable_callback);
|
||||
return _impl_gpio_disable_callback((struct device *)port, access_op,
|
||||
pin);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER1_SIMPLE(gpio_get_pending_int, K_OBJ_DRIVER_GPIO,
|
||||
struct device *);
|
||||
_SYSCALL_HANDLER(gpio_get_pending_int, port)
|
||||
{
|
||||
_SYSCALL_DRIVER_GPIO(port, get_pending_int);
|
||||
return _impl_gpio_get_pending_int((struct device *)port);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
_SYSCALL_HANDLER(i2c_configure, dev, dev_config)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_I2C);
|
||||
_SYSCALL_DRIVER_I2C(dev, configure);
|
||||
return _impl_i2c_configure((struct device *)dev, dev_config);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,20 +9,26 @@
|
|||
|
||||
_SYSCALL_HANDLER(ipm_send, dev, wait, id, data, size)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_IPM);
|
||||
_SYSCALL_DRIVER_IPM(dev, send);
|
||||
_SYSCALL_MEMORY_READ(data, size);
|
||||
return _impl_ipm_send((struct device *)dev, wait, id,
|
||||
(const void *)data, size);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER1_SIMPLE(ipm_max_data_size_get, K_OBJ_DRIVER_IPM,
|
||||
struct device *);
|
||||
_SYSCALL_HANDLER(ipm_max_data_size_get, dev)
|
||||
{
|
||||
_SYSCALL_DRIVER_IPM(dev, max_data_size_get);
|
||||
return _impl_max_data_size_get((struct device *)dev);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER1_SIMPLE(ipm_max_id_val_get, K_OBJ_DRIVER_IPM,
|
||||
struct device *);
|
||||
_SYSCALL_HANDLER(ipm_max_id_val_get, dev)
|
||||
{
|
||||
_SYSCALL_DRIVER_IPM(dev, max_id_val_get);
|
||||
return _impl_max_id_val_get((struct device *)dev);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(ipm_set_enabled, dev, enable)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_IPM);
|
||||
_SYSCALL_DRIVER_IPM(dev, set_enabled);
|
||||
return _impl_ipm_set_enabled((struct device *)dev, enable);
|
||||
}
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
|
||||
_SYSCALL_HANDLER(pinmux_pin_set, dev, pin, func)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_PINMUX);
|
||||
_SYSCALL_DRIVER_PINMUX(dev, set);
|
||||
return _impl_pinmux_pin_set((struct device *)dev, pin, func);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(pinmux_pin_get, dev, pin, func)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_PINMUX);
|
||||
_SYSCALL_DRIVER_PINMUX(dev, get);
|
||||
_SYSCALL_MEMORY_WRITE(func, sizeof(u32_t));
|
||||
return _impl_pinmux_pin_get((struct device *)dev, pin,
|
||||
(u32_t *)func);
|
||||
|
@ -24,12 +24,12 @@ _SYSCALL_HANDLER(pinmux_pin_get, dev, pin, func)
|
|||
|
||||
_SYSCALL_HANDLER(pinmux_pin_pullup, dev, pin, func)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_PINMUX);
|
||||
_SYSCALL_DRIVER_PINMUX(dev, pullup);
|
||||
return _impl_pinmux_pin_pullup((struct device *)dev, pin, func);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(pinmux_pin_input_enable, dev, pin, func)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_PINMUX);
|
||||
_SYSCALL_DRIVER_PINMUX(dev, input);
|
||||
return _impl_pinmux_pin_input_enable((struct device *)dev, pin, func);
|
||||
}
|
||||
|
|
|
@ -9,14 +9,14 @@
|
|||
|
||||
_SYSCALL_HANDLER(pwm_pin_set_cycles, dev, pwm, period, pulse)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_PWM);
|
||||
_SYSCALL_DRIVER_PWM(dev, pin_set);
|
||||
return _impl_pwm_pin_set_cycles((struct device *)dev, pwm, period,
|
||||
pulse);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(pwm_get_cycles_per_sec, dev, pwm, cycles)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_PWM);
|
||||
_SYSCALL_DRIVER_PWM(dev, get_cycles_per_sec);
|
||||
_SYSCALL_MEMORY_WRITE(cycles, sizeof(u64_t));
|
||||
return _impl_pwm_get_cycles_per_sec((struct device *)dev,
|
||||
pwm, (u64_t *)cycles);
|
||||
|
|
|
@ -7,17 +7,32 @@
|
|||
#include <syscall_handler.h>
|
||||
#include <rtc.h>
|
||||
|
||||
_SYSCALL_HANDLER1_SIMPLE(rtc_read, K_OBJ_DRIVER_RTC, struct device *);
|
||||
_SYSCALL_HANDLER(rtc_read, dev)
|
||||
{
|
||||
_SYSCALL_DRIVER_RTC(dev, read);
|
||||
return _impl_rtc_read((struct device *)dev);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER1_SIMPLE_VOID(rtc_enable, K_OBJ_DRIVER_RTC, struct device *);
|
||||
_SYSCALL_HANDLER(rtc_enable, dev)
|
||||
{
|
||||
_SYSCALL_DRIVER_RTC(dev, enable);
|
||||
return _impl_rtc_enable((struct device *)dev);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER1_SIMPLE_VOID(rtc_disable, K_OBJ_DRIVER_RTC, struct device *);
|
||||
_SYSCALL_HANDLER(rtc_disable, dev)
|
||||
{
|
||||
_SYSCALL_DRIVER_RTC(dev, disable);
|
||||
return _impl_rtc_disable((struct device *)dev);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(rtc_set_alarm, dev, alarm_val)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_RTC);
|
||||
_SYSCALL_DRIVER_RTC(dev, set_alarm);
|
||||
return _impl_rtc_set_alarm((struct device *)dev, alarm_val);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER1_SIMPLE(rtc_get_pending_int, K_OBJ_DRIVER_RTC,
|
||||
struct device *);
|
||||
_SYSCALL_HANDLER(rtc_get_pending_int, dev)
|
||||
{
|
||||
_SYSCALL_DRIVER_RTC(dev, get_pending_int);
|
||||
return _impl_rtc_get_pending_int((struct device *)dev);
|
||||
}
|
||||
|
|
|
@ -9,24 +9,27 @@
|
|||
|
||||
_SYSCALL_HANDLER(sensor_attr_set, dev, chan, attr, val)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SENSOR);
|
||||
_SYSCALL_DRIVER_SENSOR(dev, attr_set);
|
||||
_SYSCALL_MEMORY_READ(val, sizeof(struct sensor_value));
|
||||
return _impl_sensor_attr_set((struct device *)dev, chan, attr,
|
||||
(const struct sensor_value *)val);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER1_SIMPLE(sensor_sample_fetch, K_OBJ_DRIVER_SENSOR,
|
||||
struct device *);
|
||||
|
||||
_SYSCALL_HANDLER(sensor_semple_fetch_chan, dev, type)
|
||||
_SYSCALL_HANDLER(sensor_sample_sample_fetch, dev)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SENSOR);
|
||||
_SYSCALL_DRIVER_SENSOR(dev, sample_fetch);
|
||||
return _impl_sensor_sample_fetch((struct device *)dev);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(sensor_sample_fetch_chan, dev, type)
|
||||
{
|
||||
_SYSCALL_DRIVER_SENSOR(dev, sample_fetch);
|
||||
return _impl_sensor_sample_fetch_chan((struct device *)dev, type);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(sensor_channel_get, dev, chan, val)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SENSOR);
|
||||
_SYSCALL_DRIVER_SENSOR(dev, channel_get);
|
||||
_SYSCALL_MEMORY_WRITE(val, sizeof(struct sensor_value));
|
||||
return _impl_sensor_channel_get((struct device *)dev, chan,
|
||||
(struct sensor_value *)val);
|
||||
|
|
|
@ -7,18 +7,24 @@
|
|||
#include <uart.h>
|
||||
#include <syscall_handler.h>
|
||||
|
||||
#define UART_SIMPLE(name_) \
|
||||
_SYSCALL_HANDLER1_SIMPLE(name_, K_OBJ_DRIVER_UART, struct device *)
|
||||
#define UART_SIMPLE(op_) \
|
||||
_SYSCALL_HANDLER(uart_ ## op_, dev) { \
|
||||
_SYSCALL_DRIVER_UART(dev, op_); \
|
||||
return _impl_uart_ ## op_((struct device *)dev); \
|
||||
}
|
||||
|
||||
#define UART_SIMPLE_VOID(name_) \
|
||||
_SYSCALL_HANDLER1_SIMPLE_VOID(name_, K_OBJ_DRIVER_UART, \
|
||||
struct device *)
|
||||
#define UART_SIMPLE_VOID(op_) \
|
||||
_SYSCALL_HANDLER(uart_ ## op_, dev) { \
|
||||
_SYSCALL_DRIVER_UART(dev, op_); \
|
||||
_impl_uart_ ## op_((struct device *)dev); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
UART_SIMPLE(uart_err_check);
|
||||
UART_SIMPLE(err_check)
|
||||
|
||||
_SYSCALL_HANDLER(uart_poll_in, dev, p_char)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_UART);
|
||||
_SYSCALL_DRIVER_UART(dev, poll_in);
|
||||
_SYSCALL_MEMORY_WRITE(p_char, sizeof(unsigned char));
|
||||
return _impl_uart_poll_in((struct device *)dev,
|
||||
(unsigned char *)p_char);
|
||||
|
@ -26,31 +32,31 @@ _SYSCALL_HANDLER(uart_poll_in, dev, p_char)
|
|||
|
||||
_SYSCALL_HANDLER(uart_poll_out, dev, out_char)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_UART);
|
||||
_SYSCALL_DRIVER_UART(dev, poll_out);
|
||||
return _impl_uart_poll_out((struct device *)dev, out_char);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
UART_SIMPLE_VOID(uart_irq_tx_enable);
|
||||
UART_SIMPLE_VOID(uart_irq_tx_disable);
|
||||
UART_SIMPLE_VOID(uart_irq_rx_enable);
|
||||
UART_SIMPLE_VOID(uart_irq_rx_disable);
|
||||
UART_SIMPLE_VOID(uart_irq_err_enable);
|
||||
UART_SIMPLE_VOID(uart_irq_err_disable);
|
||||
UART_SIMPLE(uart_irq_is_pending);
|
||||
UART_SIMPLE(uart_irq_update);
|
||||
UART_SIMPLE_VOID(irq_tx_enable)
|
||||
UART_SIMPLE_VOID(irq_tx_disable)
|
||||
UART_SIMPLE_VOID(irq_rx_enable)
|
||||
UART_SIMPLE_VOID(irq_rx_disable)
|
||||
UART_SIMPLE_VOID(irq_err_enable)
|
||||
UART_SIMPLE_VOID(irq_err_disable)
|
||||
UART_SIMPLE(irq_is_pending)
|
||||
UART_SIMPLE(irq_update)
|
||||
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
||||
|
||||
#ifdef CONFIG_UART_LINE_CTRL
|
||||
_SYSCALL_HANDLER(uart_line_ctrl_set, dev, ctrl, val)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_UART);
|
||||
_SYSCALL_DRIVER_UART(dev, line_ctrl_set);
|
||||
return _impl_uart_line_ctrl_set((struct device *)dev, ctrl, val);
|
||||
}
|
||||
|
||||
_SYSCALL_HANDLER(uart_line_ctrl_get, dev, ctrl, val);
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_UART);
|
||||
_SYSCALL_DRIVER_UART(dev, line_ctrl_get);
|
||||
_SYSCALL_MEMORY_WRITE(val, sizeof(u32_t));
|
||||
return _impl_uart_line_ctrl_get((struct device *)dev, ctrl,
|
||||
(u32_t *)val);
|
||||
|
@ -60,7 +66,7 @@ _SYSCALL_HANDLER(uart_line_ctrl_get, dev, ctrl, val);
|
|||
#ifdef CONFIG_UART_DRV_CMD
|
||||
_SYSCALL_HANDLER(uart_drv_cmd, dev, cmd, p)
|
||||
{
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_UART);
|
||||
_SYSCALL_DRIVER_UART(dev, drv_cmd);
|
||||
return _impl_uart_drv_cmd((struct device *)dev, cmd, p);
|
||||
}
|
||||
#endif /* CONFIG_UART_DRV_CMD */
|
||||
|
|
|
@ -31,7 +31,7 @@ _SYSCALL_HANDLER(spi_transceive, dev, config_p, tx_bufs, rx_bufs)
|
|||
const struct spi_config *config = (const struct spi_config *)config_p;
|
||||
|
||||
_SYSCALL_MEMORY_READ(config, sizeof(*config));
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SPI);
|
||||
_SYSCALL_DRIVER_SPI(dev, transceive);
|
||||
|
||||
/* ssf is implicit system call stack frame parameter, used by
|
||||
* _SYSCALL_* APIs when something goes wrong.
|
||||
|
@ -71,6 +71,6 @@ _SYSCALL_HANDLER(spi_release, dev, config_p)
|
|||
const struct spi_config *config = (const struct spi_config *)config_p;
|
||||
|
||||
_SYSCALL_MEMORY_READ(config, sizeof(*config));
|
||||
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SPI);
|
||||
_SYSCALL_DRIVER_SPI(dev, release);
|
||||
return _impl_spi_release((struct device *)dev, config);
|
||||
}
|
||||
|
|
|
@ -135,35 +135,15 @@ struct k_mem_partition;
|
|||
enum k_objects {
|
||||
K_OBJ_ANY,
|
||||
|
||||
/* Core kernel objects */
|
||||
K_OBJ_ALERT,
|
||||
K_OBJ_MSGQ,
|
||||
K_OBJ_MUTEX,
|
||||
K_OBJ_PIPE,
|
||||
K_OBJ_SEM,
|
||||
K_OBJ_STACK,
|
||||
K_OBJ_THREAD,
|
||||
K_OBJ_TIMER,
|
||||
K_OBJ__THREAD_STACK_ELEMENT,
|
||||
|
||||
/* Driver subsystems */
|
||||
K_OBJ_DRIVER_ADC,
|
||||
K_OBJ_DRIVER_AIO_CMP,
|
||||
K_OBJ_DRIVER_COUNTER,
|
||||
K_OBJ_DRIVER_CRYPTO,
|
||||
K_OBJ_DRIVER_DMA,
|
||||
K_OBJ_DRIVER_FLASH,
|
||||
K_OBJ_DRIVER_GPIO,
|
||||
K_OBJ_DRIVER_I2C,
|
||||
K_OBJ_DRIVER_I2S,
|
||||
K_OBJ_DRIVER_IPM,
|
||||
K_OBJ_DRIVER_PINMUX,
|
||||
K_OBJ_DRIVER_PWM,
|
||||
K_OBJ_DRIVER_ENTROPY,
|
||||
K_OBJ_DRIVER_RTC,
|
||||
K_OBJ_DRIVER_SENSOR,
|
||||
K_OBJ_DRIVER_SPI,
|
||||
K_OBJ_DRIVER_UART,
|
||||
/** @cond
|
||||
* Doxygen should ignore this build-time generated include file
|
||||
* when genrating API documentation. Enumeration values are
|
||||
* generated during build by gen_kobject_list.py. It includes
|
||||
* basic kernel objects (e.g. pipes and mutexes) and driver types.
|
||||
*/
|
||||
#include <kobj-types-enum.h>
|
||||
/** @endcond
|
||||
*/
|
||||
|
||||
K_OBJ_LAST
|
||||
};
|
||||
|
|
|
@ -261,6 +261,25 @@ static inline int _obj_validation_check(struct _k_object *ko,
|
|||
!_obj_validation_check(_k_object_find((void *)ptr), (void *)ptr, \
|
||||
type, init), "access denied")
|
||||
|
||||
/**
|
||||
* @brief Runtime check driver object pointer for presence of operation
|
||||
*
|
||||
* Validates if the driver object is capable of performing a certain operation.
|
||||
*
|
||||
* @param ptr Untrusted device instance object pointer
|
||||
* @param api_struct Name of the driver API struct (e.g. gpio_driver_api)
|
||||
* @param op Driver operation (e.g. manage_callback)
|
||||
*/
|
||||
#define _SYSCALL_DRIVER_OP(ptr, api_name, op) \
|
||||
do { \
|
||||
struct api_name *__device__ = (struct api_name *) \
|
||||
((struct device *)ptr)->driver_api; \
|
||||
_SYSCALL_VERIFY_MSG(__device__->op != NULL, \
|
||||
"Operation %s not defined for driver " \
|
||||
"instance %p", \
|
||||
# op, __device__); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Runtime check kernel object pointer for non-init functions
|
||||
*
|
||||
|
@ -425,6 +444,8 @@ static inline int _obj_validation_check(struct _k_object *ko,
|
|||
return 0; \
|
||||
}
|
||||
|
||||
#include <driver-validation.h>
|
||||
|
||||
#endif /* _ASMLANGUAGE */
|
||||
|
||||
#endif /* CONFIG_USERSPACE */
|
||||
|
|
|
@ -117,6 +117,30 @@ def write_gperf_table(fp, eh, objs, static_begin, static_end):
|
|||
fp.write(footer)
|
||||
|
||||
|
||||
driver_macro_tpl = """
|
||||
#define _SYSCALL_DRIVER_%(driver_upper)s(ptr, op) _SYSCALL_DRIVER_GEN(ptr, op, %(driver_lower)s, %(driver_upper)s)
|
||||
"""
|
||||
|
||||
def write_validation_output(fp):
|
||||
fp.write("#ifndef __DRIVER_VALIDATION_GEN_H__\n")
|
||||
fp.write("#define __DRIVER_VALIDATION_GEN_H__\n")
|
||||
|
||||
fp.write("""#define _SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\
|
||||
do { \\
|
||||
_SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case); \\
|
||||
_SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op); \\
|
||||
} while (0)\n\n""");
|
||||
|
||||
for subsystem in subsystems:
|
||||
subsystem = subsystem.replace("_driver_api", "")
|
||||
|
||||
fp.write(driver_macro_tpl % {
|
||||
"driver_lower": subsystem.lower(),
|
||||
"driver_upper": subsystem.upper(),
|
||||
})
|
||||
|
||||
fp.write("#endif /* __DRIVER_VALIDATION_GEN_H__ */\n")
|
||||
|
||||
def parse_args():
|
||||
global args
|
||||
|
||||
|
@ -124,11 +148,14 @@ def parse_args():
|
|||
description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
|
||||
parser.add_argument("-k", "--kernel", required=True,
|
||||
parser.add_argument("-k", "--kernel", required=False,
|
||||
help="Input zephyr ELF binary")
|
||||
parser.add_argument(
|
||||
"-o", "--output", required=True,
|
||||
"-g", "--gperf-output", required=False,
|
||||
help="Output list of kernel object addresses for gperf use")
|
||||
parser.add_argument(
|
||||
"-V", "--validation-output", required=False,
|
||||
help="Output driver validation macros")
|
||||
parser.add_argument("-v", "--verbose", action="store_true",
|
||||
help="Print extra debugging information")
|
||||
args = parser.parse_args()
|
||||
|
@ -139,20 +166,26 @@ def parse_args():
|
|||
def main():
|
||||
parse_args()
|
||||
|
||||
eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems)
|
||||
syms = eh.get_symbols()
|
||||
max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
|
||||
objs = eh.find_kobjects(syms)
|
||||
if args.gperf_output:
|
||||
eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems)
|
||||
syms = eh.get_symbols()
|
||||
max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
|
||||
objs = eh.find_kobjects(syms)
|
||||
|
||||
if eh.get_thread_counter() > max_threads:
|
||||
sys.stderr.write("Too many thread objects (%d)\n" % thread_counter)
|
||||
sys.stderr.write("Increase CONFIG_MAX_THREAD_BYTES to %d\n",
|
||||
-(-thread_counter // 8))
|
||||
sys.exit(1)
|
||||
if eh.get_thread_counter() > max_threads:
|
||||
sys.stderr.write("Too many thread objects (%d)\n" % thread_counter)
|
||||
sys.stderr.write("Increase CONFIG_MAX_THREAD_BYTES to %d\n",
|
||||
-(-thread_counter // 8))
|
||||
sys.exit(1)
|
||||
|
||||
with open(args.output, "w") as fp:
|
||||
write_gperf_table(fp, eh, objs, syms["_static_kernel_objects_begin"],
|
||||
syms["_static_kernel_objects_end"])
|
||||
with open(args.gperf_output, "w") as fp:
|
||||
write_gperf_table(fp, eh, objs,
|
||||
syms["_static_kernel_objects_begin"],
|
||||
syms["_static_kernel_objects_end"])
|
||||
|
||||
if args.validation_output:
|
||||
with open(args.validation_output, "w") as fp:
|
||||
write_validation_output(fp)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
Loading…
Reference in a new issue