On Mon, 2020-10-12 at 09:54 -0600, Al Stone wrote: On 11 Oct 2020 07:39, Atish Patra wrote:
On Tue, 2020-10-06 at 17:32 -0600, Al Stone wrote:
What follows is a proposed introduction to the platform spec. I have tried to tie together all the threads of conversations and discussions that have been floating about around several topics -- profiles and platforms and interfaces, for instance -- and mold them into some sort of framework to be used in developing the content for the rest of the spec. This is the result.
Paring it down to a bare minimum, this introduction defines what we mean by 'profile' (a defined set of interfaces) and how we can in turn use a profile to define the requirements for a platform.
The next steps would be to first come to an agreement on a Linux (or rich OS) profile, and the interfaces required. After that, we would need to go through those interfaces to be sure we are clear on what we need, and we know what is yet to do. And then, voila! We have a draft spec :).
This is currently in asciidoc format. It can be easier to read in HTML and can be converted pretty easily with asciidoctor:
$ asciidoctor -d book -b html introduction.adoc
Signed-off-by: Al Stone <ahs3@...>
--------------------------------------------------------------- ------
// SPDX-License-Identifier: CC-BY-4.0 // // introduction.adoc: provide an introduction to the document // // Provide a basic introduction to the overall document, defining some // key terms and usages. //
# Introduction
This document is the RISC-V Platform Specification (RVPS).
This specification defines the hardware and firmware required to be able to install and use one or more operating systems (OSs) on a platform built around the RISC-V Instruction Set Architecture (ISA). The intent is to capture the constraints necessary for a hardware platform so that an operating system can be assured it is compatible with that platform, if the platform is in compliance with this specification.
Constraints on the hardware and firmware comprising part of a platform are key to this specification. For an OS to work correctly, it needs to be able to make some basic assumptions about the platform in order to boot; if there are too many variations possible, it becomes unmanageable for the OS vendor and could preclude using the platform at all. We would like to ensure this does not happen.
This specification also sets out any necessary constraints on the RISCV-V Instruction Set Architecture (ISA) -- at all privilege levels -- that are required to provide a consistent and predictable environment for running operating systems.
The intent is to provide only the constraints necessary, and not to restrict creativity.
## Platforms The term _platform_ has already been used several times. The definition used here is that a platform is the sum total of the hardware, firmware, and software comprising a usable computer system. Examples include smartphones, laptops, data center servers, single-board computers, tablets, and almost anything in between. While this is not terribly precise, this is intentional; this specification is not meant to constrain what a platform is, but to clarify what software can expect of it.
## Profiles The term _profile_ is frequently used in the RISC-V world. For the purposes of this specification, we use a reasonably precise definition of the term and how it is to be used. We do this since the specification itself sets down requirements on the basis of what a profile needs.
Consider a platform as being built up by connecting together a number of different interfaces -- the interfaces between hardware and firmware, or firmware and software, or software and the end-user.
What we would like to do is define just the interfaces between the objects that constitute a platform. This allows the implementations to be whatever they need to be, as long as they abide by the interface definition. For example, we may need a UEFI interface. Whether that is implemented via EDK2 source, or is an interface to linuxboot is irrelevant. The functionality defined by the interface is the important part.
Of particular interest in this specification are:
* The User Interface: how the end-user of a system interacts with it. Examples might be various Linux-, BSD- or Windows based systems; they might also include a specific application developed for a specific use.
* The Firmware Interface: how the User Interface makes use of S- mode. For example, UEFI Runtime Services, or ACPI -- the former a list of the services needed in order to allow the User Interface to work properly, and the latter a means to identify hardware that cannot identify itself.
I am not sure how to represent this without ambiguity. So how would you improve the definition?
There will be two kinds of firmware interfaces. UEFI/ACPI that will use SBI internally for some of the runtime services (Not All). For example? I've always thought the point was that UEFI Runtime Services were sufficient without having to expose anything else to to OS -- or, that at least they _should_ be. If there's something missing where Runtime Services are not sufficient, that probably needs fixing somewhere. But, this is exactly how U-Boot can provide a UEFI interface -- the OS doesn't need to know U-Boot is even there.
Current SBI interface provides these features that is outside scope of UEFI. 1. IPI, SFENCE, Hart State Management(CPU hotplug), Timer management In future, there will be RESET/SUSPEND (either direct SBI call or a detour route via PSCI), PMU extensions. Now, some of the extensions such as RESET/Suspend will be used by UEFI firmware internally. That means Linux will use UEFI runtime service and UEFI firmware will make a call to SBI implementation. However, Linux will directly need invoke SBI calls for all other and UEFI can't be used for that. Even for RESET/SUSPEND, Linux may need to use SBI calls directly if UEFI runtime services are not supported. That's why, both SBI & UEFI need to exposed to the OS for UEFI supported platforms. SBI is sufficient for non-UEFI based platforms. If UEFI Runtime Services are sufficient, whether the UEFI protocol interface uses SBI or any other mechanism internally, it's still UEFI at the interface, and it's the interface that needs to be specified, not the implementation.
That being said, there are also UEFI Boot Services; those will very likely need to rely on something like SBI when implemented, much as U-Boot would. Do I really need to specify that for the OS, though? As far as the OS is concerned, Boot Services aren't really visible.
Yes. We don't need to worry about the boot services. S-mdoe OS will still need SBI interface to interact with M-Mode in additio to that. So help me understand that; a specific example would really help me.
I hope the above example is sufficient. Non-UEFI/ACPI will completely rely on SBI.
How are going encode both these information via profile ? The idea is to specify the interface, not the implementation. For example, what RHEL needs is UEFI Runtime Services; how those are implemented doesn't really affect RHEL unless they don't work well. In that case, does this info need to be encoded?
As the interface is called firmware interface, UEFI can't be the only interface unless the implicit assumption is that SBI is must for all RISC-V platforms. May be a better definition of firmware interface is required. Here is my understanding In UEFI supported platforms Linux (S-mode) -> EDK2 (S-mode) -> EDK2 (M-mode) |-----Firmware-----------------| Linux (S-mode) -> U-Boot (S-mode) -> OpenSBI (M-mode) |-----Firmware-----------------| In non-UEFI platforms: Linux (S-mode) -> U-Boot (S-mode) -> OpenSBI (M-mode) |-----Firmware--| U-Boot is not resident after boot in this case. And so far, this approach is working with EDK2/tianocore, U-Boot, and there are some folks working on UEFI for linuxboot.
Now, I could see a different interface for enumerating hardware that does not self-identify -- DT or ACPI. The assumption is that it is always UEFI and ACPI, but that's just an assumption. UEFI and DT can also work (though not terribly interesting to RHEL, for example). The set of interface I've listed so far is just what occurred to me at the time; it is very probably incomplete.
* The Hardware Interface: what the User and Firmware Interfaces can expect to be present; in a way this is the interface to the outside world, but most likely it would be a list of the hardware components that are guaranteed to be present, and what standards they comply with.
* The Processor Interface: this interface defines what to expect of the processor. In the case of RISC-V this would include the parts of the ISA that and are not implemented.
* The Boot Interface: this is what one would see at a cold start of the system -- for the most part these days, this includes U-Boot or UEFI, though it could just as easily be linuxboot or coreboot. This would also define some of the functionality needed to boot the system, update the firmware and possibly manage the system remotely.
Are we going to add different boot interface provided by other boot loaders here as well ? Such as booti/bootm from U-Boot, coreboot/linuxboot ? Yes, that's the idea. I thought about having the firmware interface and the boot interface being the same thing but then realized that would be too prescriptive for no useful reason I could think of; as we've already seen, several of these can have a UEFI interface, too.
I agree. For each of the interfaces listed above, there is a domain of possibilities. Let us look at each domain of interfaces as an element in an n- tuple defined as follows:
``` N = { user, firmware, hardware, processor, boot } ```
Not all of the permutations of this set make sense. Not all of them are necessarily useful. However, it does allow us to provide a more precise definition of a profile -- a _profile_ is a value in **_N_**, a profile-tuple, if you will.
### An Example Profile The test of any formalism is whether or not it is usable. So, let’s define a general purpose Linux platform that could be used to run one of the various Linux distributions such as RHEL, Fedora, SuSE, Debian, ArchLinux or maybe even Gentoo and Slackware. The profile might be:
``` LinuxDistro = { Linux, UEFI, general, RV64GC, UEFI } ```
This is just an example of what _could_ be; it is not definitive. A proper profile for Linux distributions will be provided later in this specification. Regardless, this could tell us:
* The User Interface is a Linux system of some flavor. * The Firmware Interface is UEFI and ACPI, built upon SBI, so we now know how to enumerate the physical devices in Linux * The Hardware Interface is for general purpose computing -- defining this is where we would have to list what devices that implies. * The Processor Interface is RV64GC (U-mode, and S-mode) * The Boot Interface is UEFI and possibly the UEFI Shell.
And, as long as the interface definitions are fairly clear, we can now determine what would be in a platform that supports the ```LinuxDistro``` profile. It is the purview of this platform specification to (a) define the profiles of interest, and then (b) ensure that each of the terms in the n-tuple -- the interfaces -- are clearly defined.
### Other Distros While the definition of a ```LinuxDistro``` profile used above would seem to preclude non-Linux operating systems, defining a profile as a tuple gives us a way of handling this. For example, let’s suppose we define profiles for Windows and most BSD-based systems:
``` WindowsDistro = { Windows, UEFI, general, RV64GC, UEFI }
BSDDistro = { BSD, UEFI, general, RV64G, UEFI } ```
Again, these are only examples, and not definitive. Given what we know about these sorts of systems, we could assert the following:
``` LinuxDistro = WindowsDistro = BSDDistro ```
That is, all of these are essentially identical in the things that matter to this specification. We know that’s not exactly true, of course, but this does give us the tool to start reasoning about such things.
### Notation Whilst set notation is all well and good, we need something a bit more practical. For that, we can borrow from the example provided by GCC. A profile tuple would then be:
``` N = user-firmware-hardware-processor-boot ```
Or, for the example profiles listed above:
``` linux-distro = linux-uefi-general-rv64gc-uefi windows-distro = windows-uefi-general-rv64gc-uefi bsd-distro = bsd-uefi-general-rv64gc-uefi ```
For the long term, these could be converted into values and captured in firmware to be relayed to the OS, perhaps as a byte for each element of the tuple (how this is to happen is TBD). In this manner, the platform would describe itself, instead of the OS having to make an educated guess.
How about encoding this tuple in a DT ? The boot loader/firmware are parsing DT anyways. It can parse the tuple and know exactly which boot interface to be used ?
In case of desired boot interface is not available, it will fallback to the default method or a shell. As part of the boot protocol? That could make sense. On arm64, there's only one DT node used to pass info from grub2 to the kernel (for any kernel parameters).
Hrm. This makes me wonder if the boot protocol should be another part of the tuple or if there are a set of common assumptions that need to be separated out. Or, does this just fit in the Linux Documentation tree?
IMHO, it is better suited for Linux documentation tree. There will be a booting guide for RISC-V in Linux documentation anyways. We can just add the minimum but necessary profile information encoding/action there as well. ### Revisions Over time, the definitions of the elements in this profile-tuple will change. It’s simply the nature of the problem -- new hardware will be defined, and ultimately will be assumed to be present, or old hardware will get deprecated (e.g., CXL, and perhaps some day UARTs, respectively). Hence, we will need to be able to note the revision of an element definition for a profile definition to be complete. Again, we could have the firmware convey this information to the OS as an additional byte string (how is TBD). For practical use, we may wish to append the revisions to the tuple notation:
``` N = user-firmware-hardware-processor-boot:ur-fr-hr-pr-br ```
Or, for the example profiles listed above:
``` linux-distro = linux-uefi-general-rv64g-uefi:0-0-0-0 windows-distro = windows-uefi-general-rv64g-uefi:0-3-5-5 bsd-distro = bsd-uefi-general-rv64g-uefi:1-0-3-4 ```
Should the firmware need to verify the UEFI version supported with implemented? I think yes and it can done easily with DT parsing. I'm not sure I understand the question; UEFI is firmware. I don't understand what's being verified here.
I mean the version of UEFI implemented by UEFI firmware. It's not a big deal as it may fail otherwise. However, it may be helpful in future where a platform is compliant with a specific UEFI version or after only. A UEFI firmware can extract that information from the Profile tuple or Linux can throw a warning if the expected UEFI firmware version don't match. Having said that, it may be an implementation thing and doesn't need to be added to the specification. I've also only finished one cup of coffee so maybe I'm just being slow :).
### Some Notes * Profiles are _only_ a property of platforms, _not_ harts. * This section uses example profiles; these are not intended to be definitive. Proper profile definitions will appear in following sections of the specification. * This section presents the current definition of a platform- tuple. This may change as we know more.
-- Regards, Atish Thanks for the feedback, Atish! Most excellent.
-- Regards, Atish
|