diff --git a/Documentation/index.rst b/Documentation/index.rst index cc6d9ea9..1998a5b7 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -33,6 +33,7 @@ .. toctree:: :caption: PAL + pal/porting pal/host-abi .. _old-wiki: diff --git a/Documentation/oldwiki/Porting-Graphene-PAL-to-Other-hosts.md b/Documentation/oldwiki/Porting-Graphene-PAL-to-Other-hosts.md deleted file mode 100644 index 6386803b..00000000 --- a/Documentation/oldwiki/Porting-Graphene-PAL-to-Other-hosts.md +++ /dev/null @@ -1,113 +0,0 @@ -# Porting Graphene PAL to Other hosts - -## Platform Compatibility of Graphene - -Graphene adopts a similar architecture to the Drawbridge Library OS, which runs a generic library -OS on top of a Platform Adaptation Layer (PAL) to maximize platform compatibility. In this -architecture, the library OS can be easily ported to a new host by implementing only the PAL -for this new host. - -## How to Port Graphene - -To port Graphene to a new host platform, the only effort required is reimplementing the PAL on the -desired host platform. Most of the implementation should be as simple as translating the PAL API -to the native system interface of the host. The implemented PAL must support [PAL Host ABI](PAL-Host-ABI.md). - -In fact, even in the PAL source code, we expect part of the code to be host-generic. To make porting -Graphene easier, we deliberately separate the source code of PAL into three parts: - -* `Pal/lib`: All the library APIs used internally by PAL. -* `Pal/src`: Host-generic implementation. -* `Pal/src/host/`: Host-specific implementation. - -To port Graphene to a new host, we suggest starting with a clone of `Pal/src/host/Skeleton`. This -directory contains the skeleton code of all functions that need to be implemented as part of a -fully compatible PAL. Although we have tried our best to isolate any host-specific code in each -host directory, we do not guarantee that the necessary changes are only limited to these -directories. That is, you may have to modify other parts of the source code (especially the Makefile -scripts) to complete your implementation. - -## Steps of Porting PAL - -* Step 1: Fix compilation issues - -For the first step to port PAL, you want to be able to build PAL as an executable on the target -host. After cloning a host-specific directory, first modify `Makefile.am` to adjust compilation -rules such as `CC`, `CFLAGS`, `LDFLAGS`, `AS` and `ASFLAGS`. You will also have to define the name -of the loader as target `pal` in `Makefile.am.` - -* Step 2: Build a loader - -PAL needs to run on the target host like a regular executable. To run Graphene, PAL must initialize -the proper environments and load the applications as well as the library OS in the form of -Linux ELF binaries. To start the implemention of PAL loader, we suggest you begin with the following -APIs in your host-specific directory: - -1. `db_main.c`: This file must contain the entry function of your loader (the 'main()' function) -and APIs to retrieve host-specific information. The definitions of the APIs are as follows: - -+ `_DkGetPagesize`(required): Return the architecture page size of the target platform. -+ `_DkGetAllocationAlignment`(required): Return the allocation alignment (granularity) of the target - platform. Some platforms have different allocation alignments rather than the usual page-size - alignment. -+ `_DkGetAvailableUserAddressRange`(required): PAL must provide a user address range that - applications can use. None of these addresses should be used by PAL internally. -+ `_DkGetProcessId`(required): Return a unique process ID for each process. -+ `_DkGetHostId`(optional): Return a unique host ID for each host. -+ `_DkGetCPUInfo`(optional): Retrieve CPU information, such as vendor ID, model name. - -The entry function in `db_main.c` must eventually call the generic entry point `pal_main()`. -The definition of `pal_main()` is: - - /* Main initialization function */ - void pal_main( - PAL_NUM instance_id, /* current instance id */ - PAL_HANDLE manifest_handle, /* manifest handle if opened */ - PAL_HANDLE exec_handle, /* executable handle if opened */ - PAL_PTR exec_loaded_addr, /* executable addr if loaded */ - PAL_HANDLE parent_process, /* parent process if it's a child */ - PAL_HANDLE first_thread, /* first thread handle */ - PAL_STR* arguments, /* application arguments */ - PAL_STR* environments /* environment variables */ - ); - -2. `pal_host.h`: This file needs to define the member of `PAL_HANDLE` for handles of files, devices, - pipes, sockets, threads, processes, etc. - -3. `db_files.c`: To implement a basic loader, you have to specify how to open, read, and map an - executable file. At least `file_open`, `file_read`, `file_map` , `file_attrquery`, - `file_attrquerybyhdl` must be implemented to load a basic HelloWorld program. - -4. `db_memory.c`: The same as `db_files.c`, this file also contain APIs essential to PAL loader. At - least `_DkCheckMemoryMappable`, `_DkVirtualMemoryAlloc`, `_DkVirtualMemoryFree`, - `_DkVirtualMemoryProtect` must be implemented. - -5. `db_rtld.c`: This file must handle how symbols are resolved against the PAL loader itself, to - discover the entry address of the host ABI. If the PAL loader is a Linux ELF binary, you may simply - add a `link_map` to the `loaded_maps` list. Otherwise, you need to implement `resolve_rtld` - function to return addresses of the host ABI by names. - -You may implement the optional `_DkDebugAddMap` and `_DkDebugDelMap` to use a host-specific -debugger such as GDB to debug applications in Graphene. - -* Step 3: Test a HelloWorld program without loading library OS - -In `Pal/test`, we provide a test program that can run without the library OS and directly use the -PAL Host ABI. If you can successfully run a HelloWorld program, congratulations, you have a working -PAL loader. - -* Step 4: Implementing the whole PAL Host ABI - -Now it is time to complete the whole implementation of the PAL Host ABI. Once you have finished -implementation, use the regression tests to confirm whether your implementation is compatible with -the PAL Host ABI. To run the regression tests, run the following steps: - - cd Pal/regression - make regression - -* Step 5: Running Application with Library OS - -With a completely implemented PAL, you should be able to run any applications that are currently -supported by Graphene on your new platform. Please be aware you should not try to build any -application binaries on your target host. On the contrary, you should build them on a Linux host -and ship them to your target host. diff --git a/Documentation/pal/porting.rst b/Documentation/pal/porting.rst new file mode 100644 index 00000000..80ca91fe --- /dev/null +++ b/Documentation/pal/porting.rst @@ -0,0 +1,127 @@ +Porting Graphene PAL to Other hosts +=================================== + +Platform Compatibility of Graphene +---------------------------------- + +Graphene adopts a similar architecture to the Drawbridge Library OS, which runs +a generic library OS on top of a Platform Adaptation Layer (:term:`PAL`) to +maximize platform compatibility. In this architecture, the library OS can be +easily ported to a new host by implementing only the PAL for this new host. + +How to Port Graphene +-------------------- + +To port Graphene to a |~| new host platform, the only effort required is +reimplementing the PAL on the desired host platform. Most of the implementation +should be as simple as translating the PAL API to the native system interface of +the host. The implemented PAL must support :doc:`host-abi`. + +In fact, even in the PAL source code, we expect part of the code to be +host-generic. To make porting Graphene easier, we deliberately separate the +source code of PAL into three parts: + +* :file:`Pal/lib`: All the library APIs used internally by PAL. +* :file:`Pal/src`: Host-generic implementation. +* :file:`Pal/src/host/{host name}`: Host-specific implementation. + +To port Graphene to a new host, we suggest starting with a |~| clone of +:file:`Pal/src/host/Skeleton`. This directory contains the skeleton code of all +functions that need to be implemented as part of a |~| fully compatible PAL. +Although we have tried our best to isolate any host-specific code in each host +directory, we do not guarantee that the necessary changes are only limited to +these directories. That is, you may have to modify other parts of the source +code (especially the :file:`Makefile` scripts) to complete your implementation. + +Steps of Porting PAL +-------------------- + +Step 1: Fix compilation issues +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +For the first step to port PAL, you want to be able to build PAL as an +executable on the target host. After cloning a host-specific directory, first +modify :file:`Makefile.am` to adjust compilation rules such as :makevar:`CC`, +:makevar:`CFLAGS`, :makevar:`LDFLAGS`, :makevar:`AS` and :makevar:`ASFLAGS`. You +will also have to define the name of the loader as target ``pal`` in +:file:`Makefile.am.` + +Step 2: Build a loader +^^^^^^^^^^^^^^^^^^^^^^ +PAL needs to run on the target host like a regular executable. To run Graphene, +PAL must initialize the proper environments and load the applications as well as +the library OS in the form of Linux ELF binaries. To start the implemention of +PAL loader, we suggest you begin with the following APIs in your host-specific +directory: + +1. :file:`db_main.c`: This file must contain the entry function of your loader + (the ``main()`` function) and APIs to retrieve host-specific information. The + definitions of the APIs are as follows: + + + ``_DkGetPagesize`` (required): Return the architecture page size of the + target platform. + + ``_DkGetAllocationAlignment`` (required): Return the allocation alignment + (granularity) of the target platform. Some platforms have different + allocation alignments rather than the usual page-size alignment. + + ``_DkGetAvailableUserAddressRange`` (required): PAL must provide a |~| user + address range that applications can use. None of these addresses should be + used by PAL internally. + + ``_DkGetProcessId`` (required): Return a unique process ID for each + process. + + ``_DkGetHostId`` (optional): Return a unique host ID for each host. + + ``_DkGetCPUInfo`` (optional): Retrieve CPU information, such as vendor ID, + model name. + +The entry function in :file:`db_main.c` must eventually call the generic entry +point :func:`pal_main()`. The definition of :func:`pal_main()` is: + +.. doxygenfunction:: pal_main + :project: pal + +2. :file:`pal_host.h`: This file needs to define the member of + :type:`PAL_HANDLE` for handles of files, devices, pipes, sockets, threads, + processes, etc. + +3. :file:`db_files.c`: To implement a basic loader, you have to specify how to + open, read, and map an executable file. At least `file_open`, `file_read`, + `file_map`, `file_attrquery`, `file_attrquerybyhdl` must be implemented to + load a basic ``HelloWorld`` program. + +4. :file:`db_memory.c`: The same as :file:`db_files.c`, this file also contain + APIs essential to PAL loader. At least `_DkCheckMemoryMappable`, + `_DkVirtualMemoryAlloc`, `_DkVirtualMemoryFree`, `_DkVirtualMemoryProtect` + must be implemented. + +5. :file:`db_rtld.c`: This file must handle how symbols are resolved against the + PAL loader itself, to discover the entry address of the host ABI. If the PAL + loader is a Linux ELF binary, you may simply add a `link_map` to the + `loaded_maps` list. Otherwise, you need to implement `resolve_rtld` function + to return addresses of the host ABI by names. + +You may implement the optional `_DkDebugAddMap` and `_DkDebugDelMap` to use +a host-specific debugger such as GDB to debug applications in Graphene. + +Step 3: Test a HelloWorld program without loading library OS +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +In :file:`Pal/test`, we provide a test program that can run without the library +OS and directly use the :doc:`host-abi`. If you can successfully run +a |~| ``HelloWorld`` program, congratulations, you have a working PAL loader. + +Step 4: Implementing the whole PAL Host ABI +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Now it is time to complete the whole implementation of the :doc:`host-abi`. Once +you have finished implementation, use the regression tests to confirm whether +your implementation is compatible with the PAL Host ABI. To run the regression +tests, run the following steps: + +.. code-block:: sh + + cd Pal/regression + make regression + +Step 5: Running Application with Library OS +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +With a completely implemented PAL, you should be able to run any applications +that are currently supported by Graphene on your new platform. Please be aware +you should not try to build any application binaries on your target host. On the +contrary, you should build them on a Linux host and ship them to your target +host. diff --git a/Pal/src/pal_internal.h b/Pal/src/pal_internal.h index 01d80dc8..758d1264 100644 --- a/Pal/src/pal_internal.h +++ b/Pal/src/pal_internal.h @@ -245,17 +245,24 @@ extern PAL_CONTROL __pal_control; #define ALLOC_ALIGN_DOWN(addr) ALIGN_DOWN_POW2(addr, pal_state.alloc_align) #define ALLOC_ALIGN_DOWN_PTR(addr) ALIGN_DOWN_PTR_POW2(addr, pal_state.alloc_align) -/* Main initialization function */ -noreturn void pal_main ( - PAL_NUM instance_id, /* current instance id */ - PAL_HANDLE manifest_handle, /* manifest handle if opened */ - PAL_HANDLE exec_handle, /* executable handle if opened */ - PAL_PTR exec_loaded_addr, /* executable addr if loaded */ - PAL_HANDLE parent_process, /* parent process if it's a child */ - PAL_HANDLE first_thread, /* first thread handle */ - PAL_STR * arguments, /* application arguments */ - PAL_STR * environments /* environment variables */ - ); +/*! + * \brief Main initialization function + * + * This function must be called by the host-specific loader. + * + * \param instance_id current instance id + * \param manifest_handle manifest handle if opened + * \param exec_handle executable handle if opened + * \param exec_loaded_addr executable addr if loaded + * \param parent_process parent process if it's a child + * \param first_thread first thread handle + * \param arguments application arguments + * \param environments environment variables + */ +noreturn void pal_main( + PAL_NUM instance_id, PAL_HANDLE manifest_handle, PAL_HANDLE exec_handle, + PAL_PTR exec_loaded_addr, PAL_HANDLE parent_process, PAL_HANDLE first_thread, + PAL_STR* arguments, PAL_STR* environments); /* For initialization */ unsigned long _DkGetPagesize (void);