1 | .. SPDX-License-Identifier: CC-BY-SA-4.0 |
---|
2 | |
---|
3 | .. Copyright (C) 2018 Amaan Cheval <amaan.cheval@gmail.com> |
---|
4 | .. Copyright (C) 2018 embedded brains GmbH |
---|
5 | |
---|
6 | x86_64 |
---|
7 | ****** |
---|
8 | |
---|
9 | amd64 |
---|
10 | ===== |
---|
11 | |
---|
12 | This BSP offers only one variant, ``amd64``. The BSP can run on UEFI-capable |
---|
13 | systems by using FreeBSD's bootloader, which then loads the RTEMS executable (an |
---|
14 | ELF image). |
---|
15 | |
---|
16 | Currently only the console driver and context initialization and switching are |
---|
17 | functional (to a bare minimum), but this is enough to run the ``hello.exe`` sample |
---|
18 | in the RTEMS testsuite. |
---|
19 | |
---|
20 | Build Configuration Options |
---|
21 | --------------------------- |
---|
22 | |
---|
23 | There are no options available to ``configure`` at build time, at the moment. |
---|
24 | |
---|
25 | Testing with QEMU |
---|
26 | ----------------- |
---|
27 | |
---|
28 | To test with QEMU, we need to: |
---|
29 | |
---|
30 | - Build / install QEMU (most distributions should have it available on the |
---|
31 | package manager). |
---|
32 | - Build UEFI firmware that QEMU can use to simulate an x86-64 system capable of |
---|
33 | booting a UEFI-aware kernel, through the ``--bios`` flag. |
---|
34 | |
---|
35 | Building TianoCore's UEFI firmware, OVMF |
---|
36 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
---|
37 | |
---|
38 | Complete detailed instructions are available at `TianoCore's Github's wiki |
---|
39 | <https://github.com/tianocore/tianocore.github.io/wiki/How-to-build-OVMF>`_. |
---|
40 | |
---|
41 | Quick instructions (which may fall out of date) are: |
---|
42 | |
---|
43 | .. code-block:: shell |
---|
44 | |
---|
45 | $ git clone git://github.com/tianocore/edk2.git |
---|
46 | $ cd edk2 |
---|
47 | $ make -C BaseTools |
---|
48 | $ . edksetup.sh |
---|
49 | |
---|
50 | Then edit ``Conf/target.txt`` to set: |
---|
51 | |
---|
52 | .. code-block:: ini |
---|
53 | |
---|
54 | ACTIVE_PLATFORM = OvmfPkg/OvmfPkgX64.dsc |
---|
55 | TARGET = DEBUG |
---|
56 | TARGET_ARCH = X64 |
---|
57 | # You can use GCC46 as well, if you'd prefer |
---|
58 | TOOL_CHAIN_TAG = GCC5 |
---|
59 | |
---|
60 | Then run ``build`` in the ``edk2`` directory - the output should list the |
---|
61 | location of the ``OVMF.fd`` file, which can be used with QEMU to boot into a UEFI |
---|
62 | shell. |
---|
63 | |
---|
64 | You can find the ``OVMF.fd`` file like this as well in the edk2 directory: |
---|
65 | |
---|
66 | .. code-block:: shell |
---|
67 | |
---|
68 | $ find . -name "*.fd" |
---|
69 | ./Build/OvmfX64/DEBUG_GCC5/FV/MEMFD.fd |
---|
70 | ./Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd # the file we're looking for |
---|
71 | ./Build/OvmfX64/DEBUG_GCC5/FV/OVMF_CODE.fd |
---|
72 | ./Build/OvmfX64/DEBUG_GCC5/FV/OVMF_VARS.fd |
---|
73 | |
---|
74 | Boot RTEMS via FreeBSD's bootloader |
---|
75 | ----------------------------------- |
---|
76 | |
---|
77 | The RTEMS executable produced (an ELF file) needs to be placed in the FreeBSD's |
---|
78 | ``/boot/kernel/kernel``'s place. |
---|
79 | |
---|
80 | To do that, we first need a hard-disk image with FreeBSD installed on |
---|
81 | it. `Download FreeBSD's installer "memstick" image for amd64 |
---|
82 | <https://www.freebsd.org/where.html>`_ and then run the following commands, |
---|
83 | replacing paths as appropriate. |
---|
84 | |
---|
85 | .. code-block:: shell |
---|
86 | |
---|
87 | $ qemu-img create freebsd.img 8G |
---|
88 | $ OVMF_LOCATION=/path/to/ovmf/OVMF.fd |
---|
89 | $ FREEBSD_MEMSTICK=/path/to/FreeBSD-11.2-amd64-memstick.img |
---|
90 | $ qemu-system-x86_64 -m 1024 -serial stdio --bios $OVMF_LOCATION \ |
---|
91 | -drive format=raw,file=freebsd.img \ |
---|
92 | -drive format=raw,file=$FREEBSD_MEMSTICK |
---|
93 | |
---|
94 | The first time you do this, continue through and install FreeBSD. `FreeBSD's |
---|
95 | installation guide may prove useful |
---|
96 | <https://www.freebsd.org/doc/handbook/bsdinstall-start.html>`_ if required. |
---|
97 | |
---|
98 | Once installed, build your RTEMS executable (an ELF file), for |
---|
99 | eg. ``hello.exe``. We need to transfer this executable into ``freebsd.img``'s |
---|
100 | filesystem, at either ``/boot/kernel/kernel`` or ``/boot/kernel.old/kernel`` (or |
---|
101 | elsewhere, if you don't mind user FreeBSD's ``loader``'s prompt to boot your |
---|
102 | custom kernel). |
---|
103 | |
---|
104 | If your host system supports mounting UFS filesystems as read-write |
---|
105 | (eg. FreeBSD), go ahead and: |
---|
106 | |
---|
107 | 1. Mount ``freebsd.img`` as read-write |
---|
108 | 2. Within the filesystem, back the existing FreeBSD kernel up (i.e. effectively |
---|
109 | ``cp -r /boot/kernel /boot/kernel.old``). |
---|
110 | 3. Place your RTEMS executable at ``/boot/kernel/kernel`` |
---|
111 | |
---|
112 | If your host doesn't support mounting UFS filesystems (eg. most Linux kernels), |
---|
113 | do something to the effect of the following. |
---|
114 | |
---|
115 | On the host |
---|
116 | |
---|
117 | .. code-block:: shell |
---|
118 | |
---|
119 | # Upload hello.exe anywhere accessible within the host |
---|
120 | $ curl --upload-file hello.exe https://transfer.sh/rtems |
---|
121 | |
---|
122 | Then on the guest (FreeBSD), login with ``root`` and |
---|
123 | |
---|
124 | .. code-block:: shell |
---|
125 | |
---|
126 | # Back the FreeBSD kernel up |
---|
127 | $ cp -r /boot/kernel/ /boot/kernel.old |
---|
128 | # Bring networking online if it isn't already |
---|
129 | $ dhclient em0 |
---|
130 | # You may need to add the --no-verify-peer depending on your server |
---|
131 | $ fetch https://host.com/path/to/rtems/hello.exe |
---|
132 | # Replace default kernel |
---|
133 | $ cp hello.exe /boot/kernel/kernel |
---|
134 | $ reboot |
---|
135 | |
---|
136 | After rebooting, the RTEMS kernel should run after the UEFI firmware and |
---|
137 | FreeBSD's bootloader. The ``-serial stdio`` QEMU flag will let the RTEMS console |
---|
138 | send its output to the host's ``stdio`` stream. |
---|
139 | |
---|
140 | Paging |
---|
141 | ------ |
---|
142 | |
---|
143 | During the BSP's initialization, the paging tables are setup to identity-map the |
---|
144 | first 512GiB, i.e. virtual addresses are the same as physical addresses for the |
---|
145 | first 512GiB. |
---|
146 | |
---|
147 | The page structures are set up statically with 1GiB super-pages. |
---|
148 | |
---|
149 | .. note:: |
---|
150 | Page-faults are not handled. |
---|
151 | |
---|
152 | .. warning:: |
---|
153 | RAM size is not detected dynamically and defaults to 1GiB, if the |
---|
154 | configuration-time ``RamSize`` parameter is not used. |
---|
155 | |
---|
156 | Interrupt Setup |
---|
157 | --------------- |
---|
158 | |
---|
159 | Interrupt vectors ``0`` through ``32`` (i.e. 33 interrupt vectors in total) are |
---|
160 | setup as "RTEMS interrupts", which can be hooked through |
---|
161 | ``rtems_interrupt_handler_install``. |
---|
162 | |
---|
163 | The Interrupt Descriptor Table supports a total of 256 possible vectors (0 |
---|
164 | through 255), which leaves a lot of room for "raw interrupts", which can be |
---|
165 | hooked through ``_CPU_ISR_install_raw_handler``. |
---|
166 | |
---|
167 | Since the APIC needs to be used for the clock driver, the PIC is remapped (IRQ0 |
---|
168 | of the PIC is redirected to vector 32, and so on), and then all interrupts are |
---|
169 | masked to disable the PIC. In this state, the PIC may _still_ produce spurious |
---|
170 | interrupts (IRQ7 and IRQ15, redirected to vector 39 and vector 47 respectively). |
---|
171 | |
---|
172 | The clock driver triggers the initialization of the APIC and then the APIC |
---|
173 | timer. |
---|
174 | |
---|
175 | The I/O APIC is not supported at the moment. |
---|
176 | |
---|
177 | .. note:: |
---|
178 | IRQ32 is reserved by default for the APIC timer (see following section). |
---|
179 | |
---|
180 | IRQ255 is reserved by default for the APIC's spurious vector. |
---|
181 | |
---|
182 | .. warning:: |
---|
183 | Besides the first 33 vectors (0 through 32), and vector 255 (the APIC spurious |
---|
184 | vector), no other handlers are attached by default. |
---|
185 | |
---|
186 | Clock Driver |
---|
187 | ------------ |
---|
188 | |
---|
189 | The clock driver currently uses the APIC timer. Since the APIC timer runs at the |
---|
190 | CPU bus frequency, which can't be detected easily, the PIT is used to calibrate |
---|
191 | the APIC timer, and then the APIC timer is enabled in periodic mode, with the |
---|
192 | initial counter setup such that interrupts fire at the same frequency as the |
---|
193 | clock tick frequency, as requested by ``CONFIGURE_MICROSECONDS_PER_TICK``. |
---|
194 | |
---|
195 | Console Driver |
---|
196 | -------------- |
---|
197 | |
---|
198 | The console driver defaults to using the ``COM1`` UART port (at I/O port |
---|
199 | ``0x3F8``), using the ``NS16550`` polled driver. |
---|