Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bluetooth: Replace custom rand driver with standard entropy #6294

Merged
merged 2 commits into from
Mar 14, 2018

Conversation

carlescufi
Copy link
Member

No description provided.

@carlescufi
Copy link
Member Author

CC @durub

# FIXME: nRF5 RNG driver can't co-exist with Bluetooth's HAL
# implementation yet
depends on ENTROPY_GENERATOR && !BT
depends on ENTROPY_GENERATOR
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bump copyright year

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is done.

config ENTROPY_NRF5_PRI
int "RNG interrupt priority"
depends on ENTROPY_NRF5_RNG
range 0 1 if SOC_SERIES_NRF51X
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isnt 3 level of priority available now in Zephyr CM0? and 5 in CM4?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in CM4, but you are correct about CM0

depends on ENTROPY_NRF5_RNG
range 0 1 if SOC_SERIES_NRF51X
range 0 5 if SOC_SERIES_NRF52X
default 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let keep this all the way to the lowest

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK


#define RAND_DEFINE(name, len) u8_t name[sizeof(struct rand) + len] __aligned(4)

#define RAND_THREAD_THRESHOLD 4 /* at least access address */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have these as Kconfig options, and checked by controller Kconfig?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

* @retval bytes filled on success.
* @retval -ERRNO errno code on error.
*/
int entropy_nrf5_isr_get_entropy(struct device *device, u8_t *buf, u16_t len);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drop nrf5

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I would have to include it in the API and I want to avoid this at this point.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will wait for @galak

@codecov-io
Copy link

codecov-io commented Feb 21, 2018

Codecov Report

Merging #6294 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #6294   +/-   ##
=======================================
  Coverage   53.51%   53.51%           
=======================================
  Files         437      437           
  Lines       41420    41420           
  Branches     7935     7935           
=======================================
  Hits        22164    22164           
  Misses      16039    16039           
  Partials     3217     3217

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 570be1b...df4390f. Read the comment docs.

@carlescufi
Copy link
Member Author

@GiulianoFranchetto this would solve the issues in #6049


#define RAND_DEFINE(name, len) u8_t name[sizeof(struct rand) + len] __aligned(4)

#define RAND_THREAD_LEN (CONFIG_ENTROPY_NRF5_THR_THRESHOLD + 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need two more.... CONFIG_ENTROPY_NRF5_THR/ISR_SIZE, these have the "range CONFIG_ENTROPY_NRF5_THR/ISR_THRESHOLD 255"

and use (CONFIG_ENTROPY_NRF5_THR/ISR_SIZE + 1) as the context-safe ring buffer size.

# FIXME: nRF5 RNG driver can't co-exist with Bluetooth's HAL
# implementation yet
depends on ENTROPY_GENERATOR && !BT
depends on ENTROPY_GENERATOR
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is done.

pdu_ctrl_tx->llctrl.enc_rsp.skds);
rand_isr_get(sizeof(pdu_ctrl_tx->llctrl.enc_rsp.ivs),
pdu_ctrl_tx->llctrl.enc_rsp.ivs);
entropy_nrf5_isr_get_entropy(_radio.entropy,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check if these additional parameter passing has ISR overheads.

@carlescufi
Copy link
Member Author

@cvinayak addressed all your comments, including the generic API instead of an nrf5 one

Copy link
Collaborator

@galak galak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some changes to consider.

}
struct device *entropy;

entropy = device_get_binding(CONFIG_ENTROPY_NAME);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this either use the entropy handle from the radio, or is there somewhere we can initialize this once, so we don't have to call device_get_binding on every call to bt_rand()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I plan to change bt_rand later anyway, and this is only used by the BLE Host sparingly.

* @retval bytes filled on success.
* @retval -ERRNO errno code on error.
*/
static inline int entropy_isr_get_entropy(struct device *dev, u8_t *buffer,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we have _isr at the end of the function as the naming convention, I think that will be cleaner going forward (entropy_get_entropy_isr)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, will change

{
const struct entropy_driver_api *api = dev->driver_api;

__ASSERT(api->isr_get_entropy, "Callback pointer should not be NULL");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should do something like:

if (api->isr_get_entropy) {
   return ...
} else {
   return -ENOTSUP;
}

Since not every driver might support this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, will change

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is one additional branching in ISR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only with kernel asserts enabled (CONFIG_DEBUG)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cvinayak Sorry, I misread. @galak on second thought this is an ISR call, so usually critical. I'd rather __ASSERT() than return an error here.


struct entropy_nrf5_dev_data {
atomic_t user_count;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant line.

select ENTROPY_GENERATOR
select ENTROPY_NRF5_RNG if SOC_FAMILY_NRF5
select ENTROPY_NRF5_BIAS_CORRECTION if SOC_FAMILY_NRF5

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant line?

entropy_isr_get_entropy(_radio.entropy,
pdu_ctrl_tx->llctrl.enc_rsp.skds,
sizeof(pdu_ctrl_tx->llctrl.enc_rsp.skds));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant line

entropy_isr_get_entropy(_radio.entropy,
pdu_ctrl_tx->llctrl.enc_req.skdm,
sizeof(pdu_ctrl_tx->llctrl.enc_req.skdm));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant line

@carlescufi
Copy link
Member Author

@galak @cvinayak addressed your comments

@nvlsianpu
Copy link
Collaborator

I'm analyzing the algorithm. I will put opinion soon.


ret = isr((struct rand *)dev_data->isr, true);
if (ret != -EBUSY) {
ret = isr((struct rand *)dev_data->thr,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this call is made? Is this for flush random value in case of the race condition occurrence?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^^I mean the second param value - -ENOBUFS might be returned in two cases.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-ENOBUFS is returned to convey that a new rng value has not been put into ring buffer due to the ISR ring buffer being full (or no ISR ring buffer initialized). Hence, conveyed as "store" param to the next ring buffer (thread).

Same pattern of nested if-clause can be used to scale to any number of ring buffer population.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Then i understood this properly. Everything is right here.

last = rng->last;

if (first <= last) {
u8_t *d, *s;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

		u8_t *d, *s;
 		u8_t avail;
 		d = &rand[octets];
 		s = &rng->rand[first];

Put before if statement - this are code duplication.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree.

@carlescufi
Copy link
Member Author

@nvlsianpu I didn't write the driver, just ported it, so I will let @cvinayak speak about the implementation details.

d = &rand[octets];
s = &rng->rand[first];

avail = rng->count - first;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have a comment here? - like fetch bytes form upper part of random buffer.

}

if (octets && last) {
s = &rng->rand[0];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have a comment here? - like fetch bytes form lower part of random buffer.

};

#define DEV_DATA(dev) \
((struct entropy_nrf5_dev_data *)(dev)->driver_data)

static inline u8_t entropy_nrf5_get_u8(void)
static size_t get(struct rand *rng, size_t octets, u8_t *rand)
Copy link
Collaborator

@nvlsianpu nvlsianpu Feb 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible to reorganize get algorithm to two if statement:

if (last < first) {
  //  fetch bytes from upper rng buffer
  // update first, last, octets
}

if (octets && (first <= last)
{
  //  fetch bytes from lower rng buffer
}

I don't see a big sense in do so - so I just I signal this.

Copy link
Contributor

@cvinayak cvinayak Feb 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your suggestion translates to:
1 compare and 1 branch
plus
1 branch, 1 compare and 1 branch

whereas my top level if-clause translates to just 1 compare and 1 branch (my understanding).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, something like this. Code would be more compact, but cons is increased execution time.
so keep as is.

};

#define DEV_DATA(dev) \
((struct entropy_nrf5_dev_data *)(dev)->driver_data)

static inline u8_t entropy_nrf5_get_u8(void)
static size_t get(struct rand *rng, size_t octets, u8_t *rand)
Copy link
Contributor

@cvinayak cvinayak Feb 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your suggestion translates to:
1 compare and 1 branch
plus
1 branch, 1 compare and 1 branch

whereas my top level if-clause translates to just 1 compare and 1 branch (my understanding).

last = rng->last;

if (first <= last) {
u8_t *d, *s;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree.


ret = isr((struct rand *)dev_data->isr, true);
if (ret != -EBUSY) {
ret = isr((struct rand *)dev_data->thr,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-ENOBUFS is returned to convey that a new rng value has not been put into ring buffer due to the ISR ring buffer being full (or no ISR ring buffer initialized). Hence, conveyed as "store" param to the next ring buffer (thread).

Same pattern of nested if-clause can be used to scale to any number of ring buffer population.

@carlescufi
Copy link
Member Author

@cvinayak pushed a fix for the crash. The issue was the wrong pointer passed to IRQ_CONNECT()

@carlescufi
Copy link
Member Author

@nvlsianpu @galak this should be ready now

@carlescufi
Copy link
Member Author

@cvinayak I'm happy with your changes but can't approve because I submitted the PR. Can you approve instead?
@galak can you take one last look at this? we've reworked this a bit

#ifndef _NRF5_ENTROPY_H_
#define _NRF5_ENTROPY_H_

int entropy_get_entropy_thr(u8_t *buf, u16_t len);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you are using these outside of the driver, should have a bit more comment/api docs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, fixed

Copy link
Collaborator

@galak galak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't we adding these APIs entropy_get_entropy_isr & entropy_get_entropy_thr to include/entropy.h?

If they are not going to be added there, they should have an nrf namespace.

@carlescufi
Copy link
Member Author

Why aren't we adding these APIs entropy_get_entropy_isr & entropy_get_entropy_thr to include/entropy.h?

Because the issue is removing the device* parameter so that the call is faster.

@galak
Copy link
Collaborator

galak commented Feb 23, 2018

Because the issue is removing the device* parameter so that the call is faster.

How much faster? Faster that what other implementation? One in which we pass a pointer to the entropy device?

@carlescufi
Copy link
Member Author

How much faster? Faster that what other implementation? One in which we pass a pointer to the entropy device?

The issue here is that we want to be able to use a standard entropy driver for the Link Layer, which has strict timing requirements. What @cvinayak has observed is that if we don't remove the parameter from the function call, as well as optimizing with -Ofast, the ISR does not have time to complete. We are trying to reach a compromise where we use a standard driver instead of having a BLE-specific one in subsys/bluetooth/controller/hal, but at the same time we can still perform fast encryption on an nRF51.

return 0;
}

int entropy_get_entropy_thr(u8_t *buf, u16_t len)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cvinayak do we really need this one? In thread mode we could use the standard one really

@carlescufi
Copy link
Member Author

@cvinayak @galak updated after lengthy discussion

#include "hal/ecb.h"
#include "hal/ccm.h"
#include "hal/radio.h"
#include "hal/debug.h"
#include "hal/radio.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicated

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@@ -6,23 +6,28 @@

#include <soc.h>

#if defined(CONFIG_SOC_FAMILY_NRF5)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you dont need this here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@@ -5831,7 +5833,7 @@ static u32_t access_addr_get(void)
LL_ASSERT(retry);
retry--;

bt_rand(&access_addr, sizeof(u32_t));
bt_rand((u8_t *)&access_addr, sizeof(u32_t));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant change

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Copy link
Contributor

@cvinayak cvinayak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@carlescufi
Copy link
Member Author

@galak we leave this out of 1.11, ready for 1.12. That said, it still needs your approval, I think all of your initial objections have been addressed.

@durub
Copy link

durub commented Mar 8, 2018

LGTM.

Thanks, @carlescufi! I was just needing this yesterday, having this ready for 1.12 is great news -- good job.

@carlescufi carlescufi modified the milestones: v1.11.0, v1.12.0 Mar 8, 2018
@carlescufi carlescufi force-pushed the rand_entropy branch 2 times, most recently from 9803006 to b43d63e Compare March 13, 2018 19:40
Copy link
Contributor

@cvinayak cvinayak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

The rand driver present in the BLE Link Layer is able to provide
entropy for both threads and ISRs, and so it is more suited to be used
as a generic nRF5x entropy driver instead of the current one. This will
allow applications and the Link Layer to use the same driver without
duplicating it.

Signed-off-by: Carles Cufi <[email protected]>
Signed-off-by: Vinayak Kariappa Chettimada <[email protected]>
After porting the rand driver to drivers/entropy, replace the usage of
the old, Buetooth-specific driver with the generic entropy one.

Signed-off-by: Carles Cufi <[email protected]>
Signed-off-by: Vinayak Kariappa Chettimada <[email protected]>
@carlescufi carlescufi merged commit fb3387a into zephyrproject-rtos:master Mar 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants