forked from CosmosOS/Cosmos
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request CosmosOS#2281 from CosmosOS/fix/plug-documentation
Rewrite the plug text
- Loading branch information
Showing
1 changed file
with
35 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,63 +1,58 @@ | ||
# Plugs | ||
|
||
Plugs are used to fill "holes" in .NET libraries and replace them with different | ||
code. Holes exist for example when a method in .NET library uses a Windows API | ||
call. That API call will not be available on Cosmos. Emulating the win32 API would be highly inefficient. Instead, | ||
Cosmos replaces specific methods and property implementations that rely on | ||
win32 API calls. Plugs can also be used to provide an alternate implementation | ||
for a method, even if it does not rely on the Windows API. | ||
|
||
Plugs can be implemented in the following manners: | ||
## Types of plugs | ||
|
||
There are two types of plugs used and supported by Cosmos: | ||
|
||
* Code Plug - A standard C# (or any .NET language) method is used to provide the alternate implementation. | ||
* X#/Assembly Languge - In a few cases, it is difficult or impossible to write the code using C#/.Net since one needs exact control over the emitted assembly code. An assembly plug are designed for that case. Cosmos itself only uses this type of plug within the Cosmos.Core projects. | ||
|
||
## How do plugs work | ||
|
||
To explain how plugs work, we first need to give an overview of how IL2CPU works. Roughly, IL2CPU compiles a kernel using the following steps: | ||
1. IL2CPU determines a list of all methods and types which are used by the kernel. | ||
2. It then compiles each of these methods into assembly code. | ||
This is usually done by getting the list of IL instructions which make up the method and translating each of them into some corresponding assembly. | ||
3. Together with a bit of boilerplate code, the emitted assembly for all the methods is compiled using yasm. | ||
|
||
* Code Plug - Standard C# (or any .NET language) is used to provide the alternate implementation. | ||
* Assembly Languge - In a few low level cases assembly language is used. This is reserved for a few cases and only allowed in the Cosmos.Core ring. | ||
* X# - Not supported as of yet. Used in place of Assembly language. | ||
Plugs change what happens in step 2. A normal code plug means that rather taking the IL instructions from the original method, the IL instructions from the plug are used and then converted into assembly. An assembly plug directly states what asm should be emitted. | ||
|
||
When a Cosmos project is compiled, IL2CPU creates a list of plugs. When it | ||
encounters a method or property for which a plug exists, instead of using the IL | ||
contained in the existing implementation, it substitutes it with the plug version | ||
instead. | ||
# Implementing a Plug | ||
|
||
### | ||
Plug Targets | ||
While one always plugs individual methods, plugs are defined class wise. Therefore the first step to plugging any method is to define a new static class to contain all the pluggged methods for some certain type. This class must be decorated with the `Plug` attribute. The plug attribute either takes the type it is plugging(`Plug(Tpe target)`) or a string with the target name(`Plug(string targetName)`). Using the string target name is required when plugging internal or private classes. An example for a plugged class is for the Math class. https://github.com/CosmosOS/Cosmos/blob/8a8393353f1957890c5154650e29847fd22bf893/source/Cosmos.System2_Plugs/System/MathImpl.cs#L8-L9 | ||
|
||
* Source Plugs - Used to target a class library without modifiable or available source. For example the Console class in the .NET Framework. The Console class uses the Windows API, so plugs can be used to redefine the methods in the Console class to use code which interacts with Cosmos instead. For these types of plug targets, the attributes are specified on the plug implemenation since the source cannot be modified of the target. If we coud modify the source, we wouldn't need plugs. :) | ||
* Assembly Plug - Empty methods which create a sort of "abstract" class are used to define an interface to an assembly language plug. This type of plug is rare and only for the core ring. For these types of plugs, the attributes are specified on the target, rather than the implementation. | ||
## Code Plug | ||
|
||
Non-source targets should never need to use assembly language, but if they do | ||
the plugs must be cascaded since assembly language plugs can only be applied to | ||
classes with modifiable source. | ||
Once you have created such a class, you can add methods to the class. If these methods share the signature with a method in the original class they will be used to plug the original methods. For example in the above mentioned Math plug class, the following method plugs the original `double Math.Abs(double)` implementation. | ||
|
||
### | ||
Implementing a Plug | ||
https://github.com/CosmosOS/Cosmos/blob/8a8393353f1957890c5154650e29847fd22bf893/source/Cosmos.System2_Plugs/System/MathImpl.cs#L52-L63 | ||
|
||
Plugs can be applied to a class, or to an individual method or property. Plug | ||
implementations are defined by applying attributes to the class which provides | ||
the plug implementation. | ||
Note, when plugging a non-static method, the first argument will be correspond to "this" (the instance for which the method is being called). | ||
|
||
### | ||
Plug Assembly Naming in Cosmos | ||
Sometimes it is impossible to define a method with exactly the same signature due to some of the arguments being from private or internal classes. In that case you can use the `PlugMethod` attribute. An example, is the following plug for `GC.AllocateNewArray` since `ALLOC_FLAGS` is a private enum. | ||
https://github.com/CosmosOS/Cosmos/blob/8a8393353f1957890c5154650e29847fd22bf893/source/Cosmos.Core_Plugs/System/GCImpl.cs#L17-L29 | ||
|
||
Plugs assemblies in Cosmos are named in the following manner. | ||
## Assembly Plug | ||
|
||
Cosmos.<ring>.Plugs.<Unique section of target namespace> | ||
Defining an assembly plug is slightly more complicated. The first step is the same and one needs to define a method with the same signature as the method one needs to plug. This acts as plug placeholder. The actual plug implemenation is a new class inheriting from `AssemblerMethod`. This class needs to override the `void AssembleNew(Assembler aAssembler, object aMethodInfo)` method. The `AssembleNew` method will be called when IL2CPU is executing and should emit the required asm. Examples of such classes can be found [here](https://github.com/CosmosOS/Cosmos/blob/master/source/Cosmos.Core_Plugs/MathImpl.cs) including the plug implementation for `double Math.Round(double)`, | ||
|
||
ie Cosmos.System.Plugs.System | ||
https://github.com/CosmosOS/Cosmos/blob/8a8393353f1957890c5154650e29847fd22bf893/source/Cosmos.Core_Plugs/MathImpl.cs#L40-L49 | ||
|
||
Normally only one section will exist after plugs, but mutliple sections could | ||
exist to further seperate a group of plugs into multiple assemblies. In the | ||
previous example we can determine the following information: | ||
The final step is to link the plug implementation to the plug placeholder by adding a `PlugMethod(Type Assembler)` to the plug placeholder, where the `Assembler` value is the class you created with the implementation. An example is the plug placeholder for the above mentioned `double Math.Round(double)`, | ||
|
||
* **Cosmos**.System.Plugs.System - All Cosmos assemblies start with Cosmos.*. User assemblies should not use the Cosmos. prefix. | ||
* Cosmos.**System**.Plugs.System - The plugs are part of the System ring. | ||
* Cosmos.System.**Plugs**.System - Plugs seperates plugs from normal code with in the Cosmos.System.* | ||
* Cosmos.System.Plugs.**System** - The plugs in this assembly will apply to System.*. It could also be System.Collections for example to apply to System.Collections.* | ||
https://github.com/CosmosOS/Cosmos/blob/8a8393353f1957890c5154650e29847fd22bf893/source/Cosmos.Core_Plugs/MathImpl.cs#L15-L19 | ||
|
||
Plugs should be implemented in the highest ring possible and according to the | ||
code in the plug, not according to the class to which the plug targets. Most | ||
plugs should be in fact in the system ring. Except for a few special plugs | ||
needed by the compiler, off hand I cannot think of any that should be | ||
implemented in any ring lower than the system ring. | ||
## Using plugs to write assembly in your kernel | ||
|
||
**Plug Target** | ||
While plugs are usually used to overwrite existing methods in the .Net runtime, they can also be used to include assembly methods in your kernel. | ||
This is for example done to implement the `void CPU.UpdateIDT(bool)` method in Cosmos. | ||
To do this for your own classes and methods is not more difficult than plugging any other method. Simply set target of the plug class to your own class and write the assembly plug as usual. As a reference you can look at [Cosmos.Core/CPU.cs](https://github.com/CosmosOS/Cosmos/blob/master/source/Cosmos.Core/CPU.cs), [Cosmos.Core_Asm/CPUImpl.cs](https://github.com/CosmosOS/Cosmos/blob/master/source/Cosmos.Core_Asm/CPUImpl.cs) and [CPUUpdateIDTAsm.cs]( https://github.com/CosmosOS/Cosmos/blob/master/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs). | ||
|
||
Please specify the PlugTarget using the fully qualified name, like: | ||
global::System.Console. To avoid later name colisions. | ||
**Important:** All plugs must go in a seperate project, which is included in your original project using the `PlugReference` attribute in your kernels csproj. |