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:
Leandro Pereira 2018-04-04 13:50:32 -07:00 committed by Anas Nashif
parent e7ded11a2e
commit c200367b68
20 changed files with 224 additions and 119 deletions

View file

@ -364,6 +364,19 @@ add_custom_command(OUTPUT include/generated/syscall_dispatch.c ${syscall_list_h}
DEPENDS ${syscalls_json} 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.c.obj from offsets.c
# Generate offsets.h from offsets.c.obj # Generate offsets.h from offsets.c.obj
@ -376,6 +389,7 @@ target_link_libraries(offsets zephyr_interface)
add_dependencies( offsets add_dependencies( offsets
syscall_list_h_target syscall_list_h_target
syscall_macros_h_target syscall_macros_h_target
driver_validation_h_target
) )
add_custom_command( add_custom_command(
@ -782,7 +796,7 @@ if(CONFIG_USERSPACE)
${PYTHON_EXECUTABLE} ${PYTHON_EXECUTABLE}
${GEN_KOBJ_LIST} ${GEN_KOBJ_LIST}
--kernel $<TARGET_FILE:zephyr_prebuilt> --kernel $<TARGET_FILE:zephyr_prebuilt>
--output ${OBJ_LIST} --gperf-output ${OBJ_LIST}
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose> $<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
DEPENDS zephyr_prebuilt DEPENDS zephyr_prebuilt
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}

View file

@ -292,6 +292,9 @@ Several macros exist to validate arguments:
a message parameter, instead printing the expression tested if it a message parameter, instead printing the expression tested if it
fails. The latter should only be used for the most obvious of tests. 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 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 calling thread. This is done instead of returning some error condition to
keep the APIs the same when calling from supervisor mode. keep the APIs the same when calling from supervisor mode.

View file

@ -7,8 +7,19 @@
#include <adc.h> #include <adc.h>
#include <syscall_handler.h> #include <syscall_handler.h>
_SYSCALL_HANDLER1_SIMPLE_VOID(adc_enable, K_OBJ_DRIVER_ADC, struct device *); _SYSCALL_HANDLER(adc_enable, dev)
_SYSCALL_HANDLER1_SIMPLE_VOID(adc_disable, K_OBJ_DRIVER_ADC, struct device *); {
_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) _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; struct adc_seq_table *seq_table = (struct adc_seq_table *)seq_table_p;
int i; 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_READ(seq_table, sizeof(struct adc_seq_table));
_SYSCALL_MEMORY_ARRAY_READ(seq_table->entries, seq_table->num_entries, _SYSCALL_MEMORY_ARRAY_READ(seq_table->entries, seq_table->num_entries,
sizeof(struct adc_seq_entry)); sizeof(struct adc_seq_entry));

View file

@ -9,9 +9,12 @@
_SYSCALL_HANDLER(aio_cmp_disable, dev, index) _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); return _impl_aio_cmp_disable((struct device *)dev, index);
} }
_SYSCALL_HANDLER1_SIMPLE(aio_cmp_get_pending_int, K_OBJ_DRIVER_AIO, _SYSCALL_HANDLER(aio_cmp_get_pending_int, dev)
struct device *); {
_SYSCALL_DRIVER_AIO_CMP(dev, get_pending_int);
return _impl_aio_get_pending_int((struct device *)dev, index);
}

View file

@ -11,9 +11,13 @@
* instance and return an integral value * instance and return an integral value
*/ */
#define COUNTER_HANDLER(name) \ #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(get_pending_int)
COUNTER_HANDLER(counter_read); COUNTER_HANDLER(read)
COUNTER_HANDLER(counter_stop); COUNTER_HANDLER(stop)
COUNTER_HANDLER(counter_start); COUNTER_HANDLER(start)

View file

@ -13,13 +13,13 @@
_SYSCALL_HANDLER(dma_start, dev, channel) _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); return _impl_dma_start((struct device *)dev, channel);
} }
_SYSCALL_HANDLER(dma_stop, 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); return _impl_dma_stop((struct device *)dev, channel);
} }

View file

@ -9,7 +9,7 @@
_SYSCALL_HANDLER(entropy_get_entropy, dev, buffer, len) _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); _SYSCALL_MEMORY_WRITE(buffer, len);
return _impl_entropy_get_entropy((struct device *)dev, (u8_t *)buffer, return _impl_entropy_get_entropy((struct device *)dev, (u8_t *)buffer,
len); len);

View file

@ -9,7 +9,7 @@
_SYSCALL_HANDLER(flash_read, dev, offset, data, len) _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); _SYSCALL_MEMORY_WRITE(data, len);
return _impl_flash_read((struct device *)dev, offset, (void *)data, return _impl_flash_read((struct device *)dev, offset, (void *)data,
len); len);
@ -17,7 +17,7 @@ _SYSCALL_HANDLER(flash_read, dev, offset, data, len)
_SYSCALL_HANDLER(flash_write, 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); _SYSCALL_MEMORY_READ(data, len);
return _impl_flash_write((struct device *)dev, offset, return _impl_flash_write((struct device *)dev, offset,
(const void *)data, len); (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_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); 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 #ifdef CONFIG_FLASH_PAGE_LAYOUT
_SYSCALL_HANDLER(flash_get_page_info_by_offs, dev, offs, info) _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)); _SYSCALL_MEMORY_WRITE(info, sizeof(struct flash_pages_info));
return _impl_flash_get_page_info_by_offs((struct device *)dev, offs, return _impl_flash_get_page_info_by_offs((struct device *)dev, offs,
(struct flash_pages_info *)info); (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_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)); _SYSCALL_MEMORY_WRITE(info, sizeof(struct flash_pages_info));
return _impl_flash_get_page_info_by_idx((struct device *)dev, idx, return _impl_flash_get_page_info_by_idx((struct device *)dev, idx,
(struct flash_pages_info *)info); (struct flash_pages_info *)info);
} }
_SYSCALL_HANDLER1_SIMPLE(flash_get_page_count, K_OBJ_DRIVER_FLASH, _SYSCALL_HANDLER(flash_get_page_count, dev)
struct device *); {
_SYSCALL_DRIVER_FLASH(dev, page_layout);
return _impl_flash_get_page_count((struct device *)dev);
}
#endif #endif

View file

@ -9,19 +9,19 @@
_SYSCALL_HANDLER(gpio_config, port, access_op, pin, flags) _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); return _impl_gpio_config((struct device *)port, access_op, pin, flags);
} }
_SYSCALL_HANDLER(gpio_write, port, access_op, pin, value) _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); return _impl_gpio_write((struct device *)port, access_op, pin, value);
} }
_SYSCALL_HANDLER(gpio_read, 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)); _SYSCALL_MEMORY_WRITE(value, sizeof(u32_t));
return _impl_gpio_read((struct device *)port, access_op, pin, return _impl_gpio_read((struct device *)port, access_op, pin,
(u32_t *)value); (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_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, return _impl_gpio_enable_callback((struct device *)port, access_op,
pin); pin);
} }
_SYSCALL_HANDLER(gpio_disable_callback, 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, return _impl_gpio_disable_callback((struct device *)port, access_op,
pin); pin);
} }
_SYSCALL_HANDLER1_SIMPLE(gpio_get_pending_int, K_OBJ_DRIVER_GPIO, _SYSCALL_HANDLER(gpio_get_pending_int, port)
struct device *); {
_SYSCALL_DRIVER_GPIO(port, get_pending_int);
return _impl_gpio_get_pending_int((struct device *)port);
}

View file

@ -10,7 +10,7 @@
_SYSCALL_HANDLER(i2c_configure, dev, dev_config) _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); return _impl_i2c_configure((struct device *)dev, dev_config);
} }

View file

@ -9,20 +9,26 @@
_SYSCALL_HANDLER(ipm_send, dev, wait, id, data, size) _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); _SYSCALL_MEMORY_READ(data, size);
return _impl_ipm_send((struct device *)dev, wait, id, return _impl_ipm_send((struct device *)dev, wait, id,
(const void *)data, size); (const void *)data, size);
} }
_SYSCALL_HANDLER1_SIMPLE(ipm_max_data_size_get, K_OBJ_DRIVER_IPM, _SYSCALL_HANDLER(ipm_max_data_size_get, dev)
struct device *); {
_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, _SYSCALL_HANDLER(ipm_max_id_val_get, dev)
struct device *); {
_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_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); return _impl_ipm_set_enabled((struct device *)dev, enable);
} }

View file

@ -10,13 +10,13 @@
_SYSCALL_HANDLER(pinmux_pin_set, dev, pin, func) _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); return _impl_pinmux_pin_set((struct device *)dev, pin, func);
} }
_SYSCALL_HANDLER(pinmux_pin_get, 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)); _SYSCALL_MEMORY_WRITE(func, sizeof(u32_t));
return _impl_pinmux_pin_get((struct device *)dev, pin, return _impl_pinmux_pin_get((struct device *)dev, pin,
(u32_t *)func); (u32_t *)func);
@ -24,12 +24,12 @@ _SYSCALL_HANDLER(pinmux_pin_get, dev, pin, func)
_SYSCALL_HANDLER(pinmux_pin_pullup, 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); return _impl_pinmux_pin_pullup((struct device *)dev, pin, func);
} }
_SYSCALL_HANDLER(pinmux_pin_input_enable, 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); return _impl_pinmux_pin_input_enable((struct device *)dev, pin, func);
} }

View file

@ -9,14 +9,14 @@
_SYSCALL_HANDLER(pwm_pin_set_cycles, dev, pwm, period, pulse) _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, return _impl_pwm_pin_set_cycles((struct device *)dev, pwm, period,
pulse); pulse);
} }
_SYSCALL_HANDLER(pwm_get_cycles_per_sec, dev, pwm, cycles) _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)); _SYSCALL_MEMORY_WRITE(cycles, sizeof(u64_t));
return _impl_pwm_get_cycles_per_sec((struct device *)dev, return _impl_pwm_get_cycles_per_sec((struct device *)dev,
pwm, (u64_t *)cycles); pwm, (u64_t *)cycles);

View file

@ -7,17 +7,32 @@
#include <syscall_handler.h> #include <syscall_handler.h>
#include <rtc.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_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); return _impl_rtc_set_alarm((struct device *)dev, alarm_val);
} }
_SYSCALL_HANDLER1_SIMPLE(rtc_get_pending_int, K_OBJ_DRIVER_RTC, _SYSCALL_HANDLER(rtc_get_pending_int, dev)
struct device *); {
_SYSCALL_DRIVER_RTC(dev, get_pending_int);
return _impl_rtc_get_pending_int((struct device *)dev);
}

View file

@ -9,24 +9,27 @@
_SYSCALL_HANDLER(sensor_attr_set, dev, chan, attr, val) _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)); _SYSCALL_MEMORY_READ(val, sizeof(struct sensor_value));
return _impl_sensor_attr_set((struct device *)dev, chan, attr, return _impl_sensor_attr_set((struct device *)dev, chan, attr,
(const struct sensor_value *)val); (const struct sensor_value *)val);
} }
_SYSCALL_HANDLER1_SIMPLE(sensor_sample_fetch, K_OBJ_DRIVER_SENSOR, _SYSCALL_HANDLER(sensor_sample_sample_fetch, dev)
struct device *);
_SYSCALL_HANDLER(sensor_semple_fetch_chan, dev, type)
{ {
_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); return _impl_sensor_sample_fetch_chan((struct device *)dev, type);
} }
_SYSCALL_HANDLER(sensor_channel_get, dev, chan, val) _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)); _SYSCALL_MEMORY_WRITE(val, sizeof(struct sensor_value));
return _impl_sensor_channel_get((struct device *)dev, chan, return _impl_sensor_channel_get((struct device *)dev, chan,
(struct sensor_value *)val); (struct sensor_value *)val);

View file

@ -7,18 +7,24 @@
#include <uart.h> #include <uart.h>
#include <syscall_handler.h> #include <syscall_handler.h>
#define UART_SIMPLE(name_) \ #define UART_SIMPLE(op_) \
_SYSCALL_HANDLER1_SIMPLE(name_, K_OBJ_DRIVER_UART, struct device *) _SYSCALL_HANDLER(uart_ ## op_, dev) { \
_SYSCALL_DRIVER_UART(dev, op_); \
return _impl_uart_ ## op_((struct device *)dev); \
}
#define UART_SIMPLE_VOID(name_) \ #define UART_SIMPLE_VOID(op_) \
_SYSCALL_HANDLER1_SIMPLE_VOID(name_, K_OBJ_DRIVER_UART, \ _SYSCALL_HANDLER(uart_ ## op_, dev) { \
struct device *) _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_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)); _SYSCALL_MEMORY_WRITE(p_char, sizeof(unsigned char));
return _impl_uart_poll_in((struct device *)dev, return _impl_uart_poll_in((struct device *)dev,
(unsigned char *)p_char); (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_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); return _impl_uart_poll_out((struct device *)dev, out_char);
} }
#ifdef CONFIG_UART_INTERRUPT_DRIVEN #ifdef CONFIG_UART_INTERRUPT_DRIVEN
UART_SIMPLE_VOID(uart_irq_tx_enable); UART_SIMPLE_VOID(irq_tx_enable)
UART_SIMPLE_VOID(uart_irq_tx_disable); UART_SIMPLE_VOID(irq_tx_disable)
UART_SIMPLE_VOID(uart_irq_rx_enable); UART_SIMPLE_VOID(irq_rx_enable)
UART_SIMPLE_VOID(uart_irq_rx_disable); UART_SIMPLE_VOID(irq_rx_disable)
UART_SIMPLE_VOID(uart_irq_err_enable); UART_SIMPLE_VOID(irq_err_enable)
UART_SIMPLE_VOID(uart_irq_err_disable); UART_SIMPLE_VOID(irq_err_disable)
UART_SIMPLE(uart_irq_is_pending); UART_SIMPLE(irq_is_pending)
UART_SIMPLE(uart_irq_update); UART_SIMPLE(irq_update)
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
#ifdef CONFIG_UART_LINE_CTRL #ifdef CONFIG_UART_LINE_CTRL
_SYSCALL_HANDLER(uart_line_ctrl_set, dev, ctrl, val) _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); return _impl_uart_line_ctrl_set((struct device *)dev, ctrl, val);
} }
_SYSCALL_HANDLER(uart_line_ctrl_get, 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)); _SYSCALL_MEMORY_WRITE(val, sizeof(u32_t));
return _impl_uart_line_ctrl_get((struct device *)dev, ctrl, return _impl_uart_line_ctrl_get((struct device *)dev, ctrl,
(u32_t *)val); (u32_t *)val);
@ -60,7 +66,7 @@ _SYSCALL_HANDLER(uart_line_ctrl_get, dev, ctrl, val);
#ifdef CONFIG_UART_DRV_CMD #ifdef CONFIG_UART_DRV_CMD
_SYSCALL_HANDLER(uart_drv_cmd, dev, cmd, p) _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); return _impl_uart_drv_cmd((struct device *)dev, cmd, p);
} }
#endif /* CONFIG_UART_DRV_CMD */ #endif /* CONFIG_UART_DRV_CMD */

View file

@ -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; const struct spi_config *config = (const struct spi_config *)config_p;
_SYSCALL_MEMORY_READ(config, sizeof(*config)); _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 /* ssf is implicit system call stack frame parameter, used by
* _SYSCALL_* APIs when something goes wrong. * _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; const struct spi_config *config = (const struct spi_config *)config_p;
_SYSCALL_MEMORY_READ(config, sizeof(*config)); _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); return _impl_spi_release((struct device *)dev, config);
} }

View file

@ -135,35 +135,15 @@ struct k_mem_partition;
enum k_objects { enum k_objects {
K_OBJ_ANY, K_OBJ_ANY,
/* Core kernel objects */ /** @cond
K_OBJ_ALERT, * Doxygen should ignore this build-time generated include file
K_OBJ_MSGQ, * when genrating API documentation. Enumeration values are
K_OBJ_MUTEX, * generated during build by gen_kobject_list.py. It includes
K_OBJ_PIPE, * basic kernel objects (e.g. pipes and mutexes) and driver types.
K_OBJ_SEM, */
K_OBJ_STACK, #include <kobj-types-enum.h>
K_OBJ_THREAD, /** @endcond
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,
K_OBJ_LAST K_OBJ_LAST
}; };

View file

@ -261,6 +261,25 @@ static inline int _obj_validation_check(struct _k_object *ko,
!_obj_validation_check(_k_object_find((void *)ptr), (void *)ptr, \ !_obj_validation_check(_k_object_find((void *)ptr), (void *)ptr, \
type, init), "access denied") 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 * @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; \ return 0; \
} }
#include <driver-validation.h>
#endif /* _ASMLANGUAGE */ #endif /* _ASMLANGUAGE */
#endif /* CONFIG_USERSPACE */ #endif /* CONFIG_USERSPACE */

View file

@ -117,6 +117,30 @@ def write_gperf_table(fp, eh, objs, static_begin, static_end):
fp.write(footer) 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(): def parse_args():
global args global args
@ -124,11 +148,14 @@ def parse_args():
description=__doc__, description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter) formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("-k", "--kernel", required=True, parser.add_argument("-k", "--kernel", required=False,
help="Input zephyr ELF binary") help="Input zephyr ELF binary")
parser.add_argument( parser.add_argument(
"-o", "--output", required=True, "-g", "--gperf-output", required=False,
help="Output list of kernel object addresses for gperf use") 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", parser.add_argument("-v", "--verbose", action="store_true",
help="Print extra debugging information") help="Print extra debugging information")
args = parser.parse_args() args = parser.parse_args()
@ -139,20 +166,26 @@ def parse_args():
def main(): def main():
parse_args() parse_args()
eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems) if args.gperf_output:
syms = eh.get_symbols() eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems)
max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8 syms = eh.get_symbols()
objs = eh.find_kobjects(syms) max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
objs = eh.find_kobjects(syms)
if eh.get_thread_counter() > max_threads: if eh.get_thread_counter() > max_threads:
sys.stderr.write("Too many thread objects (%d)\n" % thread_counter) sys.stderr.write("Too many thread objects (%d)\n" % thread_counter)
sys.stderr.write("Increase CONFIG_MAX_THREAD_BYTES to %d\n", sys.stderr.write("Increase CONFIG_MAX_THREAD_BYTES to %d\n",
-(-thread_counter // 8)) -(-thread_counter // 8))
sys.exit(1) sys.exit(1)
with open(args.output, "w") as fp: with open(args.gperf_output, "w") as fp:
write_gperf_table(fp, eh, objs, syms["_static_kernel_objects_begin"], write_gperf_table(fp, eh, objs,
syms["_static_kernel_objects_end"]) 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__": if __name__ == "__main__":