 for having me here and thank you Shuaq, thank you Maidan for having me. This, this seminar, this mentorship session is about writing safe instructions and drivers. And what is important about this is I think what the most important part of the presentation or the things we are going to talk about is to understand what is a safe abstraction. To understand what is different between writing them, writing a subsystem for example in C and writing a subsystem in Rust. So to that end, I will give a more interaction on the difference between the concepts of unsafe and safety in Rust. And then we will go through an example of an abstraction and a very small module to show how it would look like. So the first thing is, as I said, understanding what is safety. And basically safety means non-defined behavior in your program. In C as you know, you may have an defined behavior which means memory safety issues. For example, you can have a pointer in C where you write into an address that you don't have permission to write to. You may set fault, you may override your own memory for example, your own stack, et cetera, et cetera. You may have double freeze, auto bound issues, et cetera. So all these things is what Rust is trying to attack. Those are issues that are called undefined behavior in C and Rust also has that concept. And what Rust offers is non-defined behavior in the safe subsets. There are some conditions to apply here. Basically, this is true, but there are some conditions that we need to uphold and this is what we will see today and in the example. So undefined behavior for those of you that don't know again is in the C standard is defined as use of a non-portable or onious program construct or for onious data for which the standard does not say what the compiler has to do. So it may do what you are expecting to but it may also do something completely different. In plain terms or in easy terms, it means if you invoke and if I'm here, you can see if you are, for example, you have a data race, it means that your program may do anything. Undefined in particular may change your code completely to do something you are not expecting. So that with that out of the way, I have to explain what is a safe function, what is an same function. And we will also see what is the safe code and safe code. And I will put these colors in the slides where blue, well, each color will represent a different thing and we will have four colors basically, two blue and red for safe function and safe function. And we will also have orange and a cyan colors for the safe and safe code. And these concepts are orthogonal as we will see. So the first thing we have to understand to write safe abstractions for the kernel and also for any other project really written rest is what is a safe function? And a safe function is simply a function that no matter what the context or what are the inputs to the function, for example, the parameters or the state of the program, it doesn't matter any of that. If the function cannot trigger and defend you here. And a safe function, and we will see examples of this which will make it much more critical. And a safe function is the opposite is a function that is not safe. And in Rust, you prefix these functions with the unsafe keyword. You can forget about the pink color and use pink here to show that this is a keyword but I will not, it's not one of the important colors. Basically the important colors here are safe and unsafe. And you will see why I'm using colors a bit later. So safe function to try to make it clear. There's a question, let me see. Okay, yes, let's go to that question later. So the first thing is, because sometimes it's not easy to understand what all that means. But for example, imagine that you have a pointer. We will see an example where you have a function in C that takes a pointer. There are many, many functions in C that take a pointer, right? You have a function that takes a pointer. This, normally if you use the pointer, for example, you de-reference the pointer, do you perform a load or a store in memory? Normally you don't have a way, in most cases, in some cases you may do, but in most cases you don't have a way to establish whether the pointer, for example, is valid or invalid. You may, for example, test the pointer, for example, you may test it against null. So against zero, for example. But that doesn't tell you whether the pointer is valid. Unless you follow a convention in your program and you are very, very strict on not having any pointer that is not zero invalid, then testing for zero is a good way to test for a pointer, but it's not really covering all the values that are invalid. So it's just like a way to see if it is really, like if it is zero, then for sure it's invalid, but if it is not zero, then you don't really know if it's valid or not. So a same function cannot take a pointer, like a restricted pointer, let's say, and point anywhere, and then you cannot read the reference. If you view that, you have to consider what the caller of that function has to do. When you call that function, this is all C, right? We are not talking about RAS yet, so we are in C, and we are passing a pointer to this function. When we are doing that, the caller is the one promising that the pointer is valid because function will just take it. There is no way to test whether pointer is valid or not, so the function will take it and then it will use it. For example, as I said, it will write, for example, some memory through the pointer, but there is no way to test for that. So we are trusting the caller to pass a correct or a valid pointer. So a same function cannot do that because a same function, what it's saying is you cannot have any precondition. A same function cannot have any precondition about, for example, pointers, but the validity of pointers. We will see again, try to make it that way. On the contrary, an unsafe function, going to the bottom of the slide, safe function has safety preconditions. So for example, an unsafe function, you can say to the caller, look, the pointer that you are passing has to be valid. And this is all that basically is what we do in C all the time. In C, every time we pass a pointer, in most cases or virtually all the cases in practice, everything that takes a pointer, a function that takes a pointer is unsafe in C. Again, not in all cases, you can create examples where this is not the case. For example, you should just take the pointer and you don't de-reference it. But normally if you take a pointer in C, it's because you are going to de-reference the pointer. This means that the function has a precondition. Even if normally in C we don't write it, but it has a precondition. Another way to put it again here is in terms of contracts or preconditions, some people prefer to say contracts instead of preconditions, we talk about the safety contract. So a safe function again has a safety, sorry, does not have a safety contract. So a safe function, it may be a bit shocking or counter-intuitive, but a safe function. What is promising is that there is no safety contract to uphold. The color doesn't have to do anything in particular. It can pass whatever values it wants that the function will not trigger an infamy here. While unsafe functions are the opposite. Unsafe functions are expecting the color. They need the color of the function to pass values values. Hopefully this will be more clear later. So an example to try to make this clear. Not with pointers, but with something else. With a division by zero. If you know a bit of C, which I guess all of you or most of you know, division by zero in C is undefined behavior. There is no reasonable value to give and not actually some hardware faults or traps. So the C standard says A, as we see here, A divided by B, if B is zero, this is undefined behavior. The program may do whatever it wants. And actually estimizer can use this fact to basically infer that after this line or after this call to this function, then B was not zero. Because if it was zero, then it would have been undefined behavior. So this is an unsafe function. And I said, UB is produced, if you want, is produced for any call to this function where B is zero, right? There is also another case for those of you that know a bit more about the standard or the integral arithmetic, which is if you pass the minimum of the integers and minus one, the result cannot be represented. And therefore, well, basically it's a number flow and therefore it's also undefined behavior in the C standard. So these are two cases. At this C, it has nothing to do with REST. I wanted to start with this because I think it's a very, very simple example to start with. And I always use this example. Now, what is a way to make that function, similar function, make it safe? So one way or the trivial way to do it, of course, and in this case is how REST actually does it, but not in all cases, one way to do it is for B zero, before we do division, we test if B is zero. And if B is zero, we do something else. In this case, here, I simply put abort, panic, however you want to call it, you just stop the execution. In this case, you will not trigger undefined behavior. We also test for the other case. And therefore, because we have covered all the cases of undefined behavior that we have here before, in this slide, because we are covering all the cases of undefined behavior, then we don't have undefined behavior. There is no way a color of F, there is no way a color of the function F can trigger undefined behavior. Because if you pass, basically, you have to think about all the combinations of parameters or arguments, sorry, all the combinations of inputs to that function that may produce any undefined behavior in all the possible execution flows, if you want. You also have to take into account, for example, if you have several threads, you also have to take into account data races. If you have, for example, global state, for example, a static variable in your file, and that variable, for example, is the B. So instead of having B as a parameter, you have B as a static variable, or a global variable, or something else, or external variable. If that B is zero, then you also have to take care of those kinds of things. So it's not just the arguments or the parameters, it's also all the context of the execution context, if you want. So we have talked about unsafe and safe function. And some people think safe and or unsafe, a common misconception is that safe and safe rest is this only single thing. So this is only a single concept. But it's not actually true. There is two different concepts. There is also the unsafe and safe for code. And this is also very important to understand in order to understand the rest. So here's where I start to use another code and this other code represents the different concept. We will see later how they relate. So unsafe code is code inside an unsafe block. An unsafe block is that, it says a block that we will see that has the unsafe keyword. But we can just define it easily like this with nothing else. Safe code is the opposite. It's code that is not inside an unsafe block. This means it's defaulting rest. In rest, if you write code and you don't do anything else, it will be safe code. And well, I have to define unsafe block. As I said, it's just a block of code, basically braces, which are prefixes by unsafe code. Sorry, yeah. So unsafe code or code inside an unsafe block, it has access to all operations. Basically all operations in the language. Everything you can do in the language, you can do in unsafe code. And that's basically it. That's what the unsafe code is. While safe code, you can say it's a subset of the other language, of the unsafe rest language. So you have the unsafe rest language, which is the bigger one. And then you have safe rest, which is a subset of that other language. The operations that we're gonna perform is just a few of them. And we will see a couple of them, but it's not really important to describe all the possible things. I have put here two, which are the most obvious, which are one is calling unsafe function. And here you see I put red color. And red color here means the other concept. Not the unsafe code that we have seen in orange, but the unsafe functions, which is the red, the red unsafe is, again, you have unsafe code, which is the one, the code that is inside an unsafe block. And you have unsafe functions, which are different, which are the ones that have a safety control that we saw in the previous. Another thing you can do in unsafe code, but that you cannot do in safe code is the reference in raw pointers. So you have a raw pointer, a raw pointer is what we call in C, a pointer. This is exactly the same thing. So in rest, the reference in a raw pointer, you cannot do it in safe code because the compiler cannot prove or cannot guarantee that a pointer points to anywhere by. So here it is live, it's very short. And I try to summarize and try to remove a common misconception. Also when one is learning rest or one is learning this concept, it's very common to basically mix these four colors or these four concepts together. Or if you want the concept is just one and the opposite and the other and the opposite. So in reality, two concepts is just that one is safe function and safe function and safe code and unsafe code. So to try to get the point across again, safe functions, the ones in blue, may or may not contain unsafe blocks. And unsafe function also may or may not contain unsafe blocks. So they are completely orthogonal. And actually in the language, if you use the language right now as it is in the current and the previous edition that exists of rest, it is true that unsafe functions by default imply an unsafe block in the code. But in the kernel we don't use that. There's also quite a few people that is trying to argue to separate completely the concept so not have this implicit unsafe block. So we will assume here we don't have that because this is a talk for the kernel. So we will assume when you write an unsafe function you actually have to put unsafe the orange one. You have to put unsafe steel. So it's not implicit. And we will see if you have some experience with Rust or you have seen Rust, it's easy to tell or it's easy to, I think the easiest ones to understand are safe functions that do not have any unsafe code and also unsafe functions that have unsafe code. Those are the two combinations basically of the four. These are the four combinations that make the most sense. So for example, you see here, well the samples I will go, sorry, in the four quadrants here, we see in the top left safe function with only safe code is the one that I said is an easy one to understand and we will see why. Then we also have in the bottom right corner we have the unsafe function with unsafe code and these are also easy to come up with basically. But the other two are a bit more complicated to understand. Safe functions with unsafe code is also easy to see and we will see an example. But the one that is most hard to understand or to see an example for and I will have to take a bit of time on that one is the unsafe function with only safe code. So let's start with the four examples and if you understand these examples, I think you will understand this concept and basically the rest of the talk and the rest of your Rust code and learning Rust will be much, much, much easier. So a safe function, the blue color with only safe code, the cyan color. We see here the function is trivial. If you now see, basically you know what is this function is also doing. If you don't know the Rust syntax, this fn means function, f is the name of function, x is the parameter, i32 is an integral of 52 bits long. The arrow means or shows the retina type which is the same and then the basis implementation. We don't use return, you can use it but it's automatic in Rust not to put the return for the return function if it is not the first one, basically. So this function basically adds one to the number and returns. As you see here, there is no unsafe. There is no unsafe keyword anywhere and therefore we are in the safe part of the language. We are in the safe subset and the function does not have either of these. So it's also a safe function. But this is clear. This is the most basic example and I think everybody can understand this right away. So let's go with the other. The bottom right corner that we saw in the other slide, the quadrant. And safe function with unsafe code. So here we have function. This is the one that I was describing in the beginning of the doc. It's a function that takes a pointer to the content of the pointer. So it performs a read or a load of the pointer and returns the value. And I put here in red and also in orange in the code to show you the difference and to try to make the difference very, very clear. So unsafe, the red means the function and unsafe the orange means the code. And again, as I explained this pointer P is a pointer to start in a pointer. It means the same as in C when you pass a constant pointer. So the contents of the pointer are constant. You are not going to store anything in the content. And we have a question that I think yes, it's relevant. I will answer the other one. I didn't know whether to go into the one. Let me see. So I click on Q&A or okay, I will read. I can read that for you, Miguel. There is one question in the chat that might be more relevant on your previous slide. Yeah, that one. You are showing adding plus that but X plus one can result in overflow if X is the max value. So I had the same question and then several people have the same question. Yes. These are very good questions and people that know C are rightfully asking the question. It makes perfect sense that in Rust overflow is not defined to be UB and therefore can be used in safe code. So basically plus one will not be UB. So in any case, whatever the value is of X plus one will not trigger UB. In Rust there are different ways of you have different ways of performing wrapping add, saturating add, etc. If you want to go into that, UB is undefined behavior. Sorry if that wasn't there from the beginning of the talk. UB, when I say UB, I mean undefined behavior. Basically undefined behavior as we said if you don't have I'm bringing this up, sorry. If you have undefined behavior then the program can do it. So in Rust I think we need a little bit more explanation probably for people that think and see like me. I mean as far as why is it that overflow is not an undefined behavior because you could have this value overflow as such. Yes, so that's basically the decision of the language. They could have designed the language with arithmetic being basically integrated in UB and therefore in that case we would need to put the unsafe braces here as well. But they defined because it was I guess the rationale was that it was so common that defining the integral overflow to be UB like in C basically would mean that many places in code would have unsafe. So they defined overflow not to be UB. Still it's considered an error in the language. So if you have overflow in internet it's considered an error. And your program should not have overflow. And actually there is a compiler flag or a compiler mode and in the kernel you can enable it. There's an option in the kernel hacking menu that we have to enable checking for that. So we can actually see where overflow happens if it happens. Of course there is all these things and with the example we will see later on the kernel it's still up to debate whether we should enable that flag always or not whether we should even have the option to begin with. So I don't want to say we want to enable it or not. Some people in the kernel want to enable that flag for Rust or there's not. Some people argue that this is new only code so we can right away enable the flag and keep it on forever. Yeah. So the answer is even if it's an error and it's considered an error in Rust it's not an exact behavior. So yes, that's a very good question that there is also a question in safe code is overflow statically analyzed by the compiler. No, it's just in the modes. In the mode where the compiler is not checking it's like in C except it's not an defined behavior. It will do if I'm not mistaken it will always wrap but it will not be a defined behavior per se even if it is considered a mistake. And in the other mode of the compiler where it will check it will check at runtime. It's not a static analysis. There is one in the question and answer box isn't passing in reference in Rust the same as pointers in C. Would you like to do answer that? Yeah, I can answer quickly. I didn't want to get into references because it's very long and we don't get into a lot of the Rust language but there is three or if you want to simplify there is two pointer types in Rust. One is the raw pointers which is what we call C pointers in C pointers in C, blank pointers, raw pointers and then there is the references and references come in two types which are the ser references and the mutable references or the unique references if you want and the other ones are called or exclusive, depends on who you ask you can see them in both ways and then there is the mutable or the unique references unique in some way. Sorry, I said mutable and an exclusive one and the other one is the ser or yes not unique but references are used precisely, references are in traditional language precisely because pointers in Rust are not and in C there is no way to as we were discussing before there is no way to test whether a pointer is valid or not and therefore you have to introduce another concept and the concept Rust introduced is references and those are granted by the compiler via the the board checker to be valid when you use them. You cannot construct every single possible program that you can't construct in C when you are using references basically when you are using safe code with references but nevertheless you can still construct most of the code that you care about and in the kernel even if we have to use some safe code as we will see later in the instructions you can still use references, you can still use the other things and you don't need to use pointers so much so we will see that we have well you can see in the kernel because we will not go today into much into pointers etc but you can see in the abstraction in the kernel that we have right now. We wrap for example take a file extract file from the kernel or extract new text and we have a pointer to the to the raw pointer to the C extract so the one that is defined in C and we use it like that but we don't we don't expose that pointer to the driver or to the model or to the client however you want to say okay that way basically we are hiding the raw pointer and providing a safe API so that the clients can be safe code are raster references similar to C++ reference yes and no, yes in the sense that for example they cannot be null they you cannot just have an invalid reference in C++ is to be as well but in raster references come in two flavors as I said the share and the exclusive ones or the mutable ones and then you have as well the lifetimes associated with them so references come with a static lifetime so it's not a runtime lifetime it's a static lifetime and the compiler and the borough checker uses that to ensure that the reference is valid so it's similar in a way but it's different in other ways so I would basically all raster references C pointers and C++ references are all pointer like type C1 or pointer like faceted but they are different it's not a map completely one to the other I see compile or run type panic I will have to open that let me see the question that in practice how is our flow trapped if not you will get the UB from Eric they just check the operation for example if you divide by zero they will if you see the in godwall the output you will see that they test for the if the compiler doesn't know just the miser knows for example that the B is not zero it will not put the runtime check there but otherwise that's just how they do for again for our flow for other things like the validity of the references the raster references this is not a runtime this is done at compile time so it depends basically here we can go on and on but basically for some things raster prevents UB on defined behavior via runtime checks and other times it prevents it by via compile time mechanisms so it depends it depends on which is the case that we are looking at so plain integration is defined to wrap but it's up to your program where it should be considered an error no no no in Rust it's considered an error and there are two modes in the compiler that you can use up to you or to your project depending on what you need but as far as I understand it's considered an error and your program should not overflow but it's not an defined behavior so the optimizer will not go crazy assuming that our flow cannot help that's the difference okay so let's try to go back a bit on the on the on the safe function with only safe code and the other examples because again this is the yeah please ask more questions about this because it's the perhaps not the hardest part of Rust to get or to understand but it's the key one that you have to understand to be able to write safe abstractions and understand why some things are safe and safe and how to wrap things how to model your subsystem if you are a subsystem engineer how to model your subsystem to make it safe yeah perhaps I should have used here not plus one but another operation that we didn't have to go into the overflow discussion yeah let's assume that this is an operation that is a trivial operation okay just imagine that I return just x so there is no discussion it's just an orb and it returns the identity function and it returns the same x as we have passed and then we have the other one that we were saying the unsafe function with unsafe code and this is we pass a pointer and we dereference the pointer and because the p is unrestricted if you want if p can have any value whatever the caller wants when we dereference p we have to trust the caller we are trusting whoever put the p there the argument and therefore we have to because we trust the because we are trusting the caller here we are trusting that the caller is putting a valid pointer we have to write unsafe in red so the unsafe in orange here is only because the language makes explicit where when we are in the in the superset or in the unsafe Rust language so inside those races we are allowed to dereference a pointer if I try to remove the orange color here the code will not compile okay however the red one is something that I am promising the red one is not something that is checked by the compiler the red one is something I am saying is something that I am telling the compiler this function is not safe this function needs the caller to check for the arguments the programmer needs to be trusted the caller has to be trusted there is a question not really related but I will read it could you overload a function basically a safe F and an unsafe F no you cannot overload in general you can do operate overload in Rust but there is no overload in Rust apart from that that is how you write a safe API for an unsafe code etc okay so let's continue so these are the two I think I hope these two are basically clear the two different ones and we will go to the other two quadrants which are a bit more tricky to understand this one is a safe function the one in grey with the background is a safe function with unsafe code so blue with the orange right here to make it example simple I have copied the previous slide so this is the function F I have renamed it to function J and I just call it sorry I just call it from F to the other one but the one I am talking about the safe function is the one in the bottom the one in the top highlighted with the background and what is happening here is as I told you before the function in top is unsafe and I have to write I have to in the sense that if I don't do it it's a bug okay we can go into that later I have to write the red unsafe otherwise it's a mistake and we will see what is the name of those kinds of mistakes but in the bottom one I am not writing it in the top one E is basically not bounded or not about it unrestricted if you want but in F I am passing a here these syntax may surprise you it's basically like the address of this literal so we will create some place where it can create a pointer to the literal it's just that but the the key here is that F even if we are performing we are just calling the other function which is unsafe F is safe because we are passing one pointer that we know always is valid and there is no way outside of F any color of F there is no way they can manipulate that or they can try to break break that to introduce and define behavior okay so let me see yeah there is a raise hand if you want to yeah Faith would you like to answer your question ask a question you can also put it in chat or question and answer box you can go ahead Miguel okay so I hope this one is clear I will repeat I will leave it here a few more seconds the top one is unrestricted the parameters unrestricted and therefore we have to track the color and F is passing a fixed if you want pointer to 42 wherever that maybe and we know that operation calling the other function the top function is unsafe as we saw calling an unsafe red function basically the red unsafe calling one of those functions is an unsafe operation and therefore we have to be in the unsafe subset of rest we have to use the orange unsafe to call it but since we know there is no way we don't have to trust basically that the color of F can do anything we don't have to trust the color to avoid and define behavior here so F is actually safe here okay and now the last one which basically to give any meaningful example I have to introduce quite a bit of code I will try to summarize what all this means but this is the case the last quadrant which is unsafe function with only safe code so we have a module M these are the outer races and inside we have a structure definition like in similar to C public means public in Rust it means that people or programmers outside this module can access it also basically even outside the train let's not go into that basically we have a struct definition of a struct and the struct has a pointer inside basically the same kind of pointer a pointer to a constant and we have imp here is saying the implementation of S is a way to add methods if you want to a struct but that's not please don't get to see the chat it doesn't scroll so implementation of S means adding methods and static functions constructors new here the first function that we see here new is a constructor is what usually we call constructor actually there is nothing really special about new it's not like C++ constructors new is just the normal name or the name that we give to this function and new you could say it's like a static method in the sense that it doesn't take a T-sponter doesn't take doesn't take any parameters and not even hidden parameters let's say and it returns S self here is basically a synonym or an alias for S itself so it returns an S and the S it returns which if we go into the into the function in the implementation we see it returns the same thing we were seeing in this other slide we create a pointer to somewhere that there is a 42 and we return a struct that has P initialized to that and then we have two functions more these are methods because they take the first parameter if you see the add new self and the other one the reference function has a add self parameter these are explicit in Rust they are not explicit in C++ this would be similar to the T's parameter in C++ one would be for mutable one would be for non-conce-qualified T's pointer in C++ and self would be for the conce-qualified so basically the reference is a function that cannot modify S in a way and the mutable one is the one that can modify S self is the name of the of T's like in T's in C++ it's a reference to the how you say to the receiver if you want of the call and then the other parameters and the other parameters here are for set RP which is basically we are doing a set we are saying take this pointer so we are just overwriting the pointer we don't do anything fancy there and the reference does the reference that we saw in the other example so this is basically an example that I crafted with the concept that we already saw in the other example but the key here is that the unsafe orange and the unsafe red are in different functions and so this code can perform basically the people outside this slide or this module they can create an S they can create a new one calling new and they only after having an S they can only perform two operations one is setting a new pointer into that structure and they can also de-reference it but they cannot take it to account they cannot basically someone outside M the module M they cannot perform the assignment of P by themselves so they cannot P is private to S so you cannot from outside this module you cannot overwrite P so with that in mind with those rules more ways I hope they are make a bit of sense we can now hopefully understand what is going on here so first of all de-reference in the bottom if you compare here with this function we saw we are de-referencing a P and we said we have to write the programmer has to write this is an unsafe function this should be red we should write red unsafe because we are performing something that we are trusting the caller here we are not writing the red unsafe in de-reference so this is a safe function we saw one example of this a safe function that contains a unsafe code the question is why this function is safe because we have a set in our methods and we can basically the caller or the client of this extract can control this pointer right so you may be shocking to say no no this is a de-reference if the caller can control this then it should be also unsafe but the key here is that set the set itself is unsafe so we have here a function that does not perform any unsafe code copying a pointer or assigning a pointer from one place to the other which is copying and basically copying the value of the address there is nothing special we know there is no unsafe orange unsafe in the set function and this is what may be shocking and that's why we have to construct basically this example to show one example of this kind of function let's say so how does it work a caller how does it work so why it is safe basically I'm declaring or I'm saying that this module M is sound is correct it's a module that you cannot no matter what the caller does no matter who is calling this or using this S let's say that it doesn't matter what do you do with S there is no way you can enter this only if I behave it and the reason is that if you imagine that you create a new S imagine that you create a new S with new the pointer is valid right so we know that at that point the pointer is valid then if we dereference at that point we also know that the pointer is valid because we didn't call set so the pointer is still valid this will not enter the same behavior and if they call set set is unsafe it's red unsafe it means we are trusting the caller to to give us a value of P that will not enter just introduce and defend behavior but not just in this function and this is where the the key part comes the safety boundary as they say in the safety boundary basically where we have to enforce safety is not at the level of a function the example we have seen here they are just functions these three functions and they are simple ones actually in RAST the safety boundary you enforce it at the module level so because unsafe sorry because set the set function is unsafe and this is in the same it's in a module the callers outside this module they have to be trusted to put a P a correct P value there I hope if you can see why this is the case so if we trust basically we can trust that every call to set is a correct one according to a safety contract we will see how to document that if we have a safety contract that says it has to point to a value then no matter what they do after that if they still call the reference the reference will not understand the different behavior because the set call was correct in the sense that they didn't put a P that pointed for example to man okay so this is basically an example of an unsafe function that contains only safe call and this is used well you can use it in modules to create different kinds of abstractions when another point of the safety boundary being the module in Rust is that all the code not just the code in the implementation of S all the code in a module in Rust can access the private fields so imagine that set and the reference were not methods they were outside these imp S braces if they were outside they would still be able to access the P field because they are inside the module M if they were outside the module M you cannot access the P field and this is why you can construct you can basically craft functions safe and safe ones in such a way that no matter what uses of the module not of a functional type but uses of the entire module no matter what they call with what I went you have to ensure they are all going to produce some different behavior that you mark red and safe so if you say you put red and safe in a function then you are saying I trust you and I hope you are basically you have to, if you don't do that I don't promise anything else if you pass a pointer here P that is null then the other functions that are safe I don't have, I don't promise anything so it's a conditional promise the safety promise that you are giving is this S type this module M if you want is will remain will not introduce undefined behavior as long as you play by the rules when you call set and any other unsafe functions that you may have so this is the most basic example trying to show both the safety boundaries in Rust and also a safe function that does not have actually any unsafe operation inside it and someone is asking there is a question in the chat box so if I understand this correctly the reference function is safe because the unsafe set function provides a contract that the users have to abide by yes, that's correct so how is this how is this different from say in C if you have a function that says I expect a valid value pointer and it doesn't check is that isn't this similar to that if a C function says this pointer has to be valid actually most functions are we were saying in C normally I mean it doesn't need to be the case but normally when a function in C takes a pointer if it's going to dereference it or to save it so I did later in C in C it's going to dereference it which is virtually basically all the cases unless for example you just bring the address for example right or you just I don't know but in general when you pass a pointer into a C function it's basically implicitly unsafe so all the functions in C are unsafe red is the red unsafe we have there so I understand that the main pointer might be valid but an embedded pointer might not be so it gets very complex I understand that but what I am struggling with is why would you what is the difference between this is an explicit contract in Rust how is this different from an implicit one in C that says well hey we expect valid pointers the key here is that when we have these rules and having the compiler enforce that you cannot call for example unsafe red functions unsafe functions you cannot call this set if you are in the safe subset so the key is that when you are outside of M which for example is a subsystem think about M as a subsystem together when you are outside M every client of M has an unsafe code they will not be able to cause unsafe behavior so for example if you have a driver and your driver is completely with safe code and your abstractions are correct or sound as we will see it's basically you can use both words then there is no way a driver could introduce an unsafe behavior so for example if you review you receive a driver and you don't see any unsafe orange it's a vulnerability related to an unsafe behavior memory safety that arises etc etc okay I get it so essentially the compiler is watching out for you if you were to once you say this is the contract the compiler ensures that contract is enforced if you will it ensures that you cannot call such a function from safe code but it will not check for example p is valid because it's a raw pointer there is no way you can still pass to this function now okay you can pass it if you are in unsafe code in the client and you pass now then you are breaking the contract so unsafe means the programmer is responsible for ensuring the contract for the rest of the code that is not unsafe functions sorry not unsafe functions I made a mistake here not safe and safe code not safe for those for that kind of code there is no way you can write any kind of code such that you will introduce an unsafe behavior so put another way if you imagine that you have a malicious programmer you have written a library or a subsystem in the cabinet it doesn't matter and you give this library to a programmer and you are basically that's what you are saying is no matter what code you write so not actually the inputs of a user so even a malicious programmer the one using the library what you are promising is if you have done the job correctly and the abstractions are sound what you are saying is no matter what you do as long as no matter what you do in safe and even if you mix it with unsafe as long as those unsafe contracts I have written then you will not be able to introduce an unsafe behavior so if there is any way you can use this module M to introduce a memory safety issue for example overwrite your stack let's say if there is any way you can overwrite your stack with this module M then this code is incorrect and is considered a bad and the key is that the key of this is that it allows you to analyze the code locally in the sense that I can give this module M to other people and I can more or less reasonably when I perform the manual basically analysis trying to understand whether there is a way to introduce an unsafe behavior for callers I can analyze M on its own right and not only that but it's also another layer of defense for an unsafe behavior because as long as callers stay in the safe subset or even if they use unsafe function codes so they use an orange unsafe to call set we only have to review those codes and if those codes are correct then the rest of the code will not introduce an unsafe behavior so it's basically a way to reduce the places where we actually are responsible programmers are responsible for not introducing an unsafe behavior thank you you're welcome I know it's a bit abstract to think in these terms I hope with when you start to use it it's much easier to see the benefit because in C when you program in Rust and then you go back to C basically you are always unsafe it's like in C you are in a big orange unsafe block and basically you are responsible for every single line to see whether or not to introduce an unsafe behavior if I go back for example to this function the plus one I know that's why I look at it because we are here because there is no unsafe orange block so it's very easy to analyze this code with respect to the fine behavior of course you can still have logic bugs etc ok I hope you can go through the slide offline and I hope it makes more sense so what happens if we what happens if we make a mistake so if a safe function is not actually safe the blue again then it's called unsafe or if you want you can say incorrect this is considered a bug it's not something that the compiler again the red unsafe or not writing the red unsafe and making a mistake there it's not something that the compiler is going to enforce there is no way the compiler can know whether here in this function for example there is no way well some trivial cases it could know but what I mean is that in general the compiler to know what is going to be if your module is completely sound or not so you are responsible for writing that unsafe in red if you've actually have a contract for your function but if you say this is a function that is safe but actually it's not safe so there is a way to introduce an effect behavior for colors then that is what is considered an in the standard library of Rust a CVE is assigned even if there is no software that actually exploits the vulnerability or even if there is no for example imagine in a image library you have that RISP and GIS for example and you pass some pointers to this library normally just a function that takes a pointer and the reference that pointer it's not a vulnerability or it's not a CVE you are supposed to pass a valid pointer that for example the library may have given you in another function for example a analog function you get a pointer and then you pass it to the other functions so that's not that is not considered a CVE in C but in Rust if you have a function and you allow to pass an unrestricted pointer like here in the library even if the user is supposed to pass the P that was returned by another function that would be an sound because if you don't put the red unsafe I mean because there is a way actually to trigger the fine behavior here it's as simple as passing f null calling f with null and fine behavior directly so even these cases are considered a CVE so promising that a function is safe and not actually being safe is considered a bug and a CVE is assigned in Rust and sometimes when you see these CVEs in Rust these are the kinds of CVEs they are talking about so it may be the case that actually no user of the library has actually realized any vulnerability so it's like an extra layer of defense if you want and this is the example is the other function I just removed the red unsafe so this is unsung this is a bug if you write this function it will do the same the function will do the same the function will do the same it's not that it will do something different the compiler will not treat it differently it's just that it's a bug because a caller can introduce any fine behavior with it so there is a couple of concepts I want to go through quickly some people think safe functions cannot trigger UV this is normally let's say normally this is true but there is these conditions we just spoke about that's why this is incorrect this function should not be able to trigger UV but if there is a bug in those functions for example then they are unsung and this is considered a bug so it's not true in the sense of they cannot in the sense of there is a formal guarantee or a guarantee from the compiler that you will not be able to introduce UV if the functions that you marked as safe have a bug then they are unsung and they will not have a way to introduce any fine behavior so it's not that the compiler is reviewing every implementation of a safe function but the compiler is promising is another thing but the compiler is promising is if your safe functions are sound that means if your safe functions do not have any bug like this then what it promises is that if the caller only uses safe code they will not be able to introduce any undefined behavior that the compiler is giving you but the same function has to be safe otherwise the compiler will not be able to prevent anything another misconception is unsafe block means UV will necessarily be produced and the point here is the fact that you have an unsafe block does not mean that UV will happen in fact, actually you should never have undefined behavior problem it doesn't matter unsafe blocks or not this is completely different the only thing that an unsafe block gives you is the ability to use operations that cannot be checked by the compiler for UV and therefore basically the responsibility is on you to not have UV but you still should not have UV it's not that because some people I have seen online that some people basically map these two things unsafe is UV or unsafe is related to UV and actually no, UV you cannot have UV this is the same rule as in scene, there is no difference here and coming back to the kernel a bit let me check the chat quickly so unsafe code pushes responsibility to the programmer otherwise unsafe code compiler has our back yes, unsafe unsafe code the orange unsafe pushes exactly the responsibility to the programmer when you use the orange keyword you are responsible when you write the code inside those races you are responsible for latency exactly like in see when you are in the orange unblock you are responsible for not introducing UV just like in see that means you have to every time for example you reference a pointer or you call an unsafe function you are responsible for going there and checking every single contract of the function to see you are not introducing UV that's why also normally in the kernel we follow this guideline this coding guideline we reduce the the size, not the size the length or the scope of the blocks the unsafe blocks we reduce them to the minimum possible or as reasonable basically we don't have like a big function with a single unsafe block because then you are back to see basically you are not getting anything the idea is that we reduce them to the minimum possible and actually in the guidelines as we will see in the example very very quickly now we will see that we write a comment explaining why this operation for example at the reference of a pointer why this is guaranteed by the command it's not a formal proof but it's still an explanation why the programmer that has written that line of code thinks this is not going to introduce UV in any case as for me it looks like as a warning that hey the result of that function can be UV rapidly lose unsafe and write checks I'm not sure exactly what that means it's a warning in the sense you can say it's a warning in the sense that if you write the safe function then you know you have to uphold the contract but since you have to write the orange unsafe to be able to call it the compiler will not allow you to call it by mistake so if you stay within the safe subset you don't have to worry about mistakenly calling one unsafe function that you didn't know it was unsafe for example if the caller is using an unsafe code to call a function but the only way to know if the contract is violated or not by the caller is at runtime and you don't have to know if you don't know if you don't know whether you are preventing UV the program is basically broken in a sense at least the same as in C if you have for example a program that receives an input and you don't Thomas is saying I think my question was playing with your statement what you do in unsafe code is programming responsibility let me see I will go a bit fast so in the kernel the safe and safe to split the split is referring to the I put these colors in the title but could also be understood with the other two colors as well but the split in general is the safety split the safe parts and the unsafe parts the goal in the kernel is to write drivers in safe REST and here is the C and 1 because it's basically not having unsafe blocks and ideally having the 100% of that sometimes we may not arrive to that point for example there may be some cases where we cannot we have not found a way to make an extraction safe and perform enough or fast enough sometimes you need that unsafe because you want to really, really skip check or you want to use something that you statically statically in the sense not the compiler but statically the programmer, statically the programmer knows that there is no needs for the check and there is no way to reasonably abstract that at the subsistence or the abstraction level and therefore you just write and save in the driver the point is trying to not do that the point is to write the drivers in safe REST and to keep also not just the drivers, it's easy to even if you have several subsistence subsistence sorry because the safety boundary as we explained is in the module the difference subsistence can use each other sometimes or they can be clients of a common library for example they can also use this for example if we have a common kernel in the kernel slash something we have a common facility in the kernel for something the subsistence using that facility they can also be safe so it's not that all the abstractions are completely unsafely but it's easier to see it more with the drivers and the subsistence and then calling the C side of the kernel I say here requires an unsafe block this is to explain that the bindings need to call the C side of the kernel needs an unsafe block because in C we don't have the concept of safe or unsafe we don't have a way to mark this is not going to give and define behavior no matter what so anytime you call C functions it's understood to be unsafe okay and that's why the reason we are hoping I mean we enforce it we don't enforce it with a tooling check but we hope we will be able to do that soon to remove every single call to the C side and force drivers to go through the abstractions so you should not write a driver that calls the bindings in the example code that we will not have much time to go through there today but I have uploaded some code I will show and I try to show both ways of doing it and I hope you will see the advantage of the good way compared to the bad way so basically having no abstractions compared to having the abstractions the other one will link the second one please so here is again an explanation of the driver in the left side mostly or ideally we use only safe functions that are written in the kernel grade the kernel grade this may change in the future but the point is the subsystem or abstractions it doesn't matter that it's a single grade or it's a lot of grades we have subsystem that provides some for example a GPIO subsystem and provides some safe functions and hopefully the driver will be able to use to be written only with safe functions or with the minimum possible unsafe codes so that basically reviewing a driver is very easy but then the subsystems will use unsafe codes they will use unsafe forage because they have to make those codes and they will use unsafe functions coming from the C-side and that's why we here in the bottom part we say forbidden we are trying to forbid or we are hoping that we can enforce this statically and strictly in the kernel so that nobody from the driver calls the C-bind and directly and that's why we are doing this, it's not that we want to write abstractions it's that we think there is a lot of value in writing abstractions and making this safe abstraction this is also we will skip this, this is a bit of the grades so the setup very quickly so that you can play with this if you want these instructions that you will see here in the slides that they will share these are basically the instructions that apply today but since we are changing things and the abstractions themselves and everything may change in the near future these always prevent that in a way please always follow the latest that you can find for the checkout of the tree that you have done in documentation rust, quick start so the setup you can check out the rust branch in this first link this is where development is happening and the second one I created a mentor branch with a very very trivial example code that we will see now that you can play with if you want so that you see basically all the pieces coming together but very very simple it's not like a real driver or anything like that then there is the LLBM 2 chain I explain here that you have to preferably you should use LLBM 1 builds Clam should also work I mean Clam, the compiler and not the rest of the toolchain should work, the GCC builds work in some configurations but this is very very experimental this is basically a hack that we have in place for the moment so if you really need to use it go ahead and use it but there are maybe some configurations that do not work at and in all cases even if you want to use the GCC builds not to install LLBM for example that you need LLBM installing your system somewhere a recent enough person of Clam and LLBM the rest of the toolchain I saw here in the slides how to install it there are several ways in the documentation that we explain how to install this toolchain there is ways to verify the signatures etc. but here is basically the simple one the one that is recommended by the rush language and it's quite straightforward to install you can install for whatever you can also choose which target to install etc. you also need after that you also need to install the standard library resources because we have to compile for the kernel target that we are using we have to compile core which is the very basic or not the basic but the things that do not depend on an allocator or on an operating system we can read more on that on the split of the standard library in Rust between freestanding and the other ones and it's just this command it's very quick then you install binding for installing binding you use cargo it's the only place where well that one and the tests but it's the only two places where we need cargo right now and binding you install like this you put cargo install locked version and it will download the code and compile so the example subsystem I wanted to show you can read more about it offline perhaps we don't have a lot of time but it created a driver's mental folder it's a key value store provides a few addresses I will explain this as we go this is the header very simple this is the entire subsystem basically we have a public interface that consists of two functions two an address which is just an integer here it's just an address concepts analyze it in some way the valid address is go from 0 to 5 accessing any other address is considered a UB so for example imagine that this is not an address an integer but it's something else and we will dereference something or we will read something else let's say it's considered if you can answer that about the recording later perhaps yes the recording will be uploaded so there are two functions one is pure C and the other one is a macro as we have in the kernel many macros so it's just a macro it doesn't make sense here in the example but it's to show you that sometimes we have macros in the kernel we have to call these macros from REST and then we have a private part client sooner news for example this mental read that is the one that the macro calls the underscores don't see here but if you are suing you will see the underscores the macro mental read calls the underscore underscore mental read function so this is our subsystem and we want to write some we want to use it from REST right so we have the first thing we have to do is create the bindings the bindings are REST code it's just REST code the declarations that you want of the C functions so that we can call them from REST and we can do this by hand but I mean we could do it in particular yeah thank you waiting for so and that so it's just REST code declarations of C functions but instead of doing it manually right now we put the list of headers that we want to use from REST this will probably change but for now we just have a list in this place in this file and we just include the headers we want here it will automatically be called by the build system by Kibir then for things that ByteN cannot really reasonably map to REST for example the mental read was a macro and it was not like a trivial macro it was not a constant for example so we actually need to invoke the macro in a C file and then call that function this is a if you want to say it's a bit of a conversion process if we really have REST the kernel probably we will want to have instead of having these helpers here perhaps we want to have these as real functions in the C side but for a moment we keep them here not to pollute the other parts of the kernel it's a small file so far but we have to address this but for a moment you will have to put in this REST helpers.c file this function and you have to prefix it with this REST underscore helper so that the whole mechanism works because there is a bit of magic so that it basically creates the binding with this name and it will pick that name so this C file is just invoking the macro so that the C compiler takes care of the macros and we can call this helper from REST so now in the REST module very quickly this is boilerplate I don't have time to explain everything but the module exclamation mark that you see here the same things that we use with the module underscore description module underscore author etc everything is done with a single macro implication like this so we hope that this way is simpler than in the C case but this is basically how this is how we are doing it right now the other things are not important the use part is like an include and the other things that you see in the top doesn't really matter the feature and no STD doesn't really matter the feature so an implementation and I don't have time to go through this one but you can read it offline this will be an implementation without a safe abstraction which is basically breaking the rule that we have or that we want to have of not calling the binding directly so as you see here there is this orange if you try to see the orange if you look for the orange and save blocks you will see that we are doing actually calls to the bindings to the C function so we won't talk about that and it means that if we do this in the bottom I say there in the command we can produce undefined behavior just like in C because at this point we are not really gaining much it's true that outside those unsafe blocks this is safe call but still you have to basically review every single of these unsafe orange things you don't gain anything or you don't gain you don't gain anything inside those blocks it would be like calling the function in C there is no difference so how do we write a safe abstraction boilerplate here the extractions are all the extractions of the subsystems you want are currently in Rust kernel these also may change in the future in the top part we see a couple of definitions we see a function that is called isvalid that just compares with the addresses that we have so that we know whether the address is valid or not for our subsystem and the important part is this there is a read function that we have created in this abstraction of the C subsystem with the documentation and everything so I have to mention several things here one is first of all the documentation looks like this this is marked down I think fairly easy to write there is some conventions to follow we try to follow these conventions we try to follow several of them we try to do things similar to the standard library in Rust there is for example you can see in the top part you can see square brackets with the back ticks read total writes this is a link that will be automatically by the documentation system automatically picked and links for example in elix it would be if you have used elixr or a cross-referencer that will be a link automatically generating the documentation so you can click there and you don't need to put any link it will be automatically done the example you see a symbol in the beginning a hash that means it's hidden that part of the example because only the only interested part for the people reading the documentation is the one that doesn't have that and the key here is that as you see we have used a trivial way or in this case maybe depending on what you are doing it may be the only way of doing it or not here we check first the address and then if the address is not valid we return an error you see here how we return errors in Rust and otherwise we return that the address is valid we return that the function was successful and we perform the read or explain better with the front read and then we return the the wrapped result of the read in an okay value which is basically one of the variants of the result and the key here is that the coding convention is that we write this safety comment in uppercase this safety comment is what we write before every single orange block before every single orange basically before the gate of going into the unsafe language we write this safety comment and we explain why we have we think this code is thank you Omega we explain why this this code is safe or this code is sound sorry so why there is no way because the read the Rust function is safe we have not written the unsafe read so this read whatever address it takes it is actually on the frame behavior and if we don't have this if conditional if we don't check that then we are passing the address directly like if it was a pointer and then it we will treat it on the frame behavior in the example code I have uploaded what you can play with this basically I instead of treating it on the frame behavior I just write in the log you have treated on the frame behavior but a very very simple like the most trivial example of how you could prevent on the frame behavior if you can't do such things in many cases you will not be able to sometimes for example if you use pointers pointer like things you would have to use references in Rust but this is like the most simple example if we remove so the point is if we remove the is valid check this must be an unsafe function otherwise it would be unsung because address is not restricted and therefore there is no the color of read can put anything the write is similar I will not go into that much then we have another one that I separated you can see more in the example is that I separated the addresses that were writable and the one that was not writable was only readable etc then you can create a documentation I showed you because it's very simple and the documentation is key for the last part it's very very important documentation because we have to provide for those functions that are unsafe read we have to write an unsafe safety section and those we really need to do because otherwise there is no way someone can actually verify everything otherwise in C sometimes it's implicit and you have to check the you have to check the implementation in Rust we are trying to I mean it's not that we are trying we are doing it sometimes we currently there may be some missing but the point is that we are following the convention the same as in the Rust standard library where we have to put the safety contract in every single function that is unsafe and similarly we have to put the orange for the orange blocks you have to put the safety command which is different from the safety contracts the same is the same distinction as the safe and safe function and safe and safe code it's the same we have the safety contracts for the function that are unsafe and we have the safety command for the orange blocks for the actual operation that may be may introduce you so generating the code documentation is very easy and I hope you like how quick it is there is no need to install the spin there is no need to nothing you don't have to install anything else it comes from the normal Rust execution and the documentation if you look into the generated files in Rust doc right now it will look like this so your documentation will look quite nice just with few not much effort and the re-total writes as you saw there is clickable and the examples look like that so it's quite nice then the test you can write tests something trivial like this where we check the addresses whether they are valid we assert on all that they are valid and we run these tests right now we only run the tests in the host so there are some limitations that you have to know which kind of test you can run or not but in the future the idea is that we have all the tests so basically the same as the self tests and the key need tests everything in the same place so the overhead there is no checks for the defi the calls are exactly like in C there is overhead for example if you do a you have to call a macro for example there is no inlining there is no cross language inlining it's supposed to work and I think we can make it work in the kernel but right now it's not working the cross language LTO so there is no inlining if we make that work I think the overhead will be much slower of course if you have runtime checks because you have not found a way to make the extraction safe in any other way but please know that and this is key to understand please know that in C you also have to have these checks perhaps you don't have them in the same place but you have to have somewhere you have to prove that you are not introducing UV because if you have UV you have a vulnerability or a logic bug or something else so the not logic bug so what I mean is a bug that corrupts your memory even if it's not a vulnerability per se you have to have some checks at least you have to have some checks in C as well so it's not that the rest is introducing more checks sometimes it's easier to do that to make a function safe but in some other cases and that's the hard work it's trying to make the extractions safe as fast at the same time let me go ahead this is how you run the tests you can see it offline how you format the code and back to the REST module this is what it is I put a slide where instead of having this was a linear code where we use the REST unsafe blocks and with a safe extraction it looks like this so there is no anymore unsafe blocks so my driver or my module here I know just by looking at it that there is no unsafe blocks I know there is no way I can trigger and defend behavior again this only holds this promise only holds in the abstraction all these two functions if this code is sound then the driver here will not have any defend behavior no matter what the driver developer writes and that's the key thing and that's why we want to write abstractions and not just call directly the seaside and this is basically the most important thing to realize the syntax and all the things and the features of REST there are many things that you have to understand to be able to write abstractions properly but the key value of REST that we want to to the kernel is precisely this that we can write most of the code in the safe subset and I will try to take a couple of questions really quick you have questions and Q&A yes sorry when I call a safe function do I have to take it on trust that the writer of that function has coded the data that the safe code is being used safely or does the compiler check it if you call a safe function that contains some safe you are trust basically there are two places where someone is trusting someone else one is you are calling the safe function there you are trusting that the safe function doesn't have a back that allows to introduce and defend behavior the implementation of that function to any other function that it calls it's also trusting those other functions and for the unsafe orange block that you have inside that function that is you you are the responsible of actually making sure because it's an orange block basically it's telling the compiler I will check this it's something I have to check because you cannot check it so you will have to be responsible for that is REST unwrapped consider safe or unsafe is safe because they unwrapped the trigger and defend behavior there is another version that actually I unwrapped it's an optional result if you are talking about that one and I introduced one for the unsafe person or the unchecked person if you want where you are the caller are the one that you have to ensure that the result of the option are the value that you expect will binding support DCC in the future so we have that in the list of things we want and we hope in the future yes DCC will support sorry binding we support DCC so basically binding we hope that we will have another backing so that we can have complete or full kernel builds with DCC and full kernel builds with LRBM completely dependent but for the moment this is not the case we hope funding or some people or perhaps ourselves in the future we can take on that challenge and ask questions how much effort you need to redefine those constants and basic utility functions every balance are redefining CCO to be usable and so on so the basic things and the general infrastructure things we hope that we cover as much as we can ourselves in the rest of the system let's say we are trying to show we are trying to write actual drivers so many things that you need are covered but many others are not for example if you run to write a GPIO driver there are no instructions yet you have to write them if you are the first one doing it and you probably we have to work with the maintainers first to see if they want actually to take in their tree an instruction would be a concern for increasing the amount of duplicates going the kernel based on going on forward so the first question would be a concern for increasing the amount of duplicates code we are not duplicating content and sensual we are trying to do is duplicating a sense but we are not duplicating the subsistence we are as far as we can not always but as far as we can we are wrapping the C side so we keep the C side the same and then we write the RAS the RAS part that calls the C for example mutex mutex is we use the mutex from C but we wrap it in RAS and you use it as if it was a RAS mutex but in reality you are using the C1 and the last Ion hardcoder low levels hardware software boundary system primary language DC what is a reasonable way to start with RAS you can go into LPC recordings we have some introduction of that I think the RAS webpage is very nice there is also an embedded book if you have already read the RAS book there is also other books as well and there is quite a lot of resources for embedded not much yet but we hope with the kernel work we also trigger much more people to start in low level and embedded is there any support or plans to support generating FF5s for C to call RAS well I don't we don't have time more so the questions keep coming but ok this is the last one is there any support or plans to support generating FF5s for C to call RAS so there is binding that generates that way but there is also C binding yes I think it's called C binding that is the other way around so Eric asked start with the better RAS book no I would start with the official book and then go to the other books there are books for several topics so I would start with the official book or the programming RAS is another very good book on RAS for low level C programmers and in my opinion on memory management DC between RAS and Golang I think that I think it's out of scope but for Golang or the Golang there is no way I mean I don't want to say there is no way but basically for a kernel I think RAS is a much more much better language for a kernel because it's like C it allows you to manipulate memory and to manage memory explicitly there is no GC at all I don't know if I could continue I don't have any problem but yeah we are right at time thank you so much Miguel for going over all of the questions and answers that our participants had today thank you all so much for joining us and thank you Shua for your guidance through the session as well the session is recorded and will be on the Lenox foundation YouTube page later today along with the copy of the presentation slides they'll be added to the Lenox foundation website and we hope you're able to join us for future sessions thank you so much everyone have a wonderful day thank you