Some very old changes commited now.
This commit is contained in:
parent
96a3f23670
commit
b79ae8996b
32
TODO
Normal file
32
TODO
Normal file
@ -0,0 +1,32 @@
|
||||
Roadmap:
|
||||
✔ Higher half booting in long mode
|
||||
✔ Virtual memory management
|
||||
☐ Physical memory manager
|
||||
✔ Single page
|
||||
☐ Multiple page blocks
|
||||
☐ Multithreading
|
||||
✔ Task switching
|
||||
✔ Separate address spaces
|
||||
☐ Forking?
|
||||
☐ SSE
|
||||
✔ Enable SSE instructions
|
||||
✔ Save SSE registers on task switch
|
||||
☐ Symmetric multiprocessing
|
||||
☐ User mode code execution
|
||||
☐ Syscall interface
|
||||
☐ Decide kernel architecture
|
||||
- Monolitic kernel?
|
||||
- Microkernel?
|
||||
|
||||
Documentation:
|
||||
✔ Toolchain
|
||||
✔ Booting
|
||||
✔ Memory management
|
||||
✔ Libc in kernel space
|
||||
✔ ACPI tables
|
||||
✔ APIC, IOAPIC, APIC timer
|
||||
☐ SSE
|
||||
☐ Framebuffer
|
||||
|
||||
|
||||
https://pubs.opengroup.org/onlinepubs/9699919799/
|
@ -17,8 +17,8 @@ This contains the IDT entry number for the spurious interupt handler (`0xFF`) an
|
||||
To test that the APIC works, an interrupt can be triggered by writing to the APIC Interrupt Command Registers.
|
||||
|
||||
```c
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x310)) = 0;
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x300)) = 0x50;
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x310) = 0;
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x300) = 0x50;
|
||||
```
|
||||
|
||||
This should fire interrupt 0x50.
|
||||
@ -105,7 +105,7 @@ static void ioapic_write(int reg, uint32_t value) {
|
||||
In order to know where to redirect an interrupt the IOAPIC looks into its I/O Redirection Table. This can be set up by writing to some registers.
|
||||
While IOWIN is 32 bits wide, each IOREDTBL entry is 64 bits, so two read or write operations are required to register `0x10 + 2*IRQ` and `0x11 + 2*IRQ`.
|
||||
|
||||
```
|
||||
```c
|
||||
static uint64_t ioapic_read_redirection(int irq) {
|
||||
union iored retval;
|
||||
retval.l = ioapic_read(0x10 + 2*irq);
|
||||
@ -171,9 +171,9 @@ The APIC timer can be set up in periodic mode to fire an interrupt every set num
|
||||
Then set the Timer Mode bit to Periodic and write an interrupt vector to the Local Vector Table entry for the APIC Timer:
|
||||
|
||||
```c
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x3E0)) = 0xB;
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x380)) = microseconds * calibration_factor;
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x320)) = 1<<17 | timer_interrupt;
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x3E0) = 0xB;
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x380) = microseconds * calibration_factor;
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x320) = 1<<17 | timer_interrupt;
|
||||
```
|
||||
|
||||
Since the cpu bus clock varies from machine to machine, the `calibration_factor` needs to be calculated or measured. A simple measurement method is as follows:
|
||||
@ -189,9 +189,9 @@ The APIC timer is monotonically decreasing and triggers when it reaches zero, so
|
||||
Setting the divisor, masking its interrupt and setting the initual count will start it counting down immediately:
|
||||
|
||||
```c
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x3E0)) = 0xB;
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x380)) = 0xFFFFFFFF;
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x320)) = 1<<16;
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x3E0) = 0xB;
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x380) = 0xFFFFFFFF;
|
||||
*(uint32_t *)P2V(APIC_BASE + 0x320) = 1<<16;
|
||||
```
|
||||
|
||||
For the known interval, I'll use the legacy Programmable Interval Timer - PIT.
|
||||
@ -228,7 +228,7 @@ while(!(inb(0x61) & 0x20));
|
||||
|
||||
Then finally, the remaining count is read from the APIC timer and the calibration factor is calculated. Note that this is not read from the same register as the initial count is written to:
|
||||
```c
|
||||
uint32_t remaining = *(uint32_t *)P2V(APIC_BASE + 0x390));
|
||||
uint32_t remaining = *(uint32_t *)P2V(APIC_BASE + 0x390);
|
||||
```
|
||||
|
||||
## A note about the Red Zone
|
||||
|
87
documentation/7 - sse.md
Normal file
87
documentation/7 - sse.md
Normal file
@ -0,0 +1,87 @@
|
||||
# Using SSE
|
||||
|
||||
Stream SIMD Extensions (SSD) is a set of processor instructions that help with floating point operations. They have been around for over 20 years, but are not enabled by default.
|
||||
|
||||
The reason for this is that the SSE instructions make use of some special CPU registers, and the OS needs to be aware of this so they can be saved and restored at context switching.
|
||||
|
||||
TODO: Three versions of SSE instructions and registers?
|
||||
|
||||
## Preserving registers
|
||||
|
||||
Saving and restoring the SSE registers is actually very easy, and there's even special instructions that does it:
|
||||
|
||||
```asm
|
||||
.global sse_save
|
||||
sse_save:
|
||||
fxsave [rdi]
|
||||
ret
|
||||
|
||||
.global sse_restore
|
||||
sse_restore:
|
||||
fxrstor [rdi]
|
||||
ret
|
||||
```
|
||||
|
||||
Those functions will save or restore the SSE registers to or from the 512 byte buffer used as the first argument (passed in `rdi`).
|
||||
A good time to do this is to restore the registers right before switching to a new thread, and saving them right after:
|
||||
|
||||
```c
|
||||
process *next = scheduler_next();
|
||||
...
|
||||
sse_restore(next->sse);
|
||||
switch_stack(scheduler->stack_ptr, next->stack_ptr);
|
||||
sse_save(next->sse);
|
||||
...
|
||||
```
|
||||
|
||||
TODO: Can SSE usage be checked through exceptions?
|
||||
|
||||
Now, before moving on to how to actually enable SSE, there's one pitfall to look out for.
|
||||
|
||||
The memory location for storing the SSE registers MUST BE 16 BYTE ALLIGNED.
|
||||
This is easiest done by allocation 16 bytes extra, and adding an offset to the pointer:
|
||||
|
||||
TODO: Make sure this is freed correctly!
|
||||
|
||||
```c
|
||||
struct process *new_process() {
|
||||
...
|
||||
void *sse = malloc(512+16);
|
||||
new->sse = (void *) (((uintptr_t)sse + 0xF) & ~0xF);
|
||||
```
|
||||
|
||||
## Enabling SSE
|
||||
|
||||
Ok, so finally - enabling SSE.
|
||||
|
||||
This is simply done by setting or unsetting four controll register bits.
|
||||
|
||||
```asm
|
||||
sse_init:
|
||||
mov rax, cr4
|
||||
or rax, 1<<9 //; Enable Operating System FXSAVE/FXRSTOR Support bit (OSFXSR)
|
||||
or rax, 1<<10 //; Enable Operating System Unmasked Exception Support bit (OSXMMEXCPT)
|
||||
mov cr4, rax
|
||||
|
||||
mov rax, cr0
|
||||
or rax, 1<<1 //; Enable Monitor Coprocessor bit (MP)
|
||||
and rax, ~(1<<2) //; Disable Emulate Coprocessor bit (EM)
|
||||
mov cr0, rax
|
||||
```
|
||||
|
||||
And that's it.
|
||||
We can now use floating point math!
|
||||
|
||||
TODO: Find out and explain what the flags actually do and why they are all needed.
|
||||
OSFXSR: Enable use of legacy SSE instructions and indicate that OS saves 64 and 128 bit registers on task switching
|
||||
OSXMMEXCPT: Indicate that floating point excetion (#XF) is handled by the OS
|
||||
|
||||
MP: CHECK IF THIS IS REQUIRED HERE OR ALREADY SET
|
||||
EM: Should be set to 1 if processor supports x86 - check if this is set already
|
||||
|
||||
CR0= 0x80000011
|
||||
EM already unset, MP not set
|
||||
CR4= 0x00000020
|
||||
|
||||
CR0= 0x80000013
|
||||
CR4= 0x00000620
|
27
toolchain/cross-compiler/binutils/build.sh
Normal file
27
toolchain/cross-compiler/binutils/build.sh
Normal file
@ -0,0 +1,27 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
TARGET=x86_64-elf-mittos
|
||||
SYSROOT=/opt/sysroot
|
||||
|
||||
binutils_version=binutils-2.38
|
||||
|
||||
mkdir -p /opt/external && cd /opt/external
|
||||
[ -f "${binutils_version}.tar.gz" ] || wget "http://ftp.gnu.org/gnu/binutils/${binutils_version}.tar.gz"
|
||||
[ -d "${binutils_version}" ] || tar -xf ${binutils_version}.tar.gz
|
||||
|
||||
mkdir -p build-binutils && cd build-binutils
|
||||
|
||||
|
||||
if ! grep -q mittos ../${binutils_version}/config.sub; then
|
||||
sed -i '/^case $os in$/a \\tmittos*) ;;' ../${binutils_version}/config.sub
|
||||
fi
|
||||
|
||||
../${binutils_version}/configure \
|
||||
--target=${TARGET} \
|
||||
--with-sysroot=${SYSROOT} \
|
||||
--disable-nls \
|
||||
--disable-werror \
|
||||
CC="x86_64-elf-gcc"
|
||||
|
||||
# make
|
||||
# make install
|
30
toolchain/ports/cairo/build.sh
Normal file
30
toolchain/ports/cairo/build.sh
Normal file
@ -0,0 +1,30 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
TARGET=x86_64-elf
|
||||
SYSROOT=/opt/sysroot
|
||||
|
||||
cairo_version=cairo-1.16.0
|
||||
|
||||
mkdir -p /opt/external && cd /opt/external
|
||||
[ -f "${cairo_version}.tar.xz" ] || wget "https://www.cairographics.org/releases/${cairo_version}.tar.xz"
|
||||
[ -d "${cairo_version}" ] || tar -xf ${cairo_version}.tar.xz
|
||||
|
||||
mkdir -p build-cairo && cd build-cairo
|
||||
rm -rf *
|
||||
../${cairo_version}/configure \
|
||||
--target=${TARGET} \
|
||||
--prefix=${SYSROOT}/usr \
|
||||
--enable-xlib=no \
|
||||
--enable-png=no \
|
||||
--enable-script=no \
|
||||
--enable-ps=no \
|
||||
--enable-pdf=no \
|
||||
--enable-svg=no \
|
||||
--enable-interpreter=no \
|
||||
--enable-shared=no \
|
||||
--enable-gtk-doc-html=no \
|
||||
CFLAGS="-DCAIRO_NO_MUTEX=1 -mcmodel=large -mno-red-zone -O0 -ggdb" \
|
||||
PKG_CONFIG_PATH="${SYSROOT}/usr/lib/pkgconfig"
|
||||
|
||||
make
|
||||
make install
|
20
toolchain/ports/pixman/build.sh
Normal file
20
toolchain/ports/pixman/build.sh
Normal file
@ -0,0 +1,20 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
TARGET=x86_64-elf
|
||||
SYSROOT=/opt/sysroot
|
||||
|
||||
pixman_version=pixman-0.40.0
|
||||
|
||||
mkdir -p /opt/external && cd /opt/external
|
||||
[ -f "${pixman_version}.tar.gz" ] || wget "https://www.cairographics.org/releases/${pixman_version}.tar.gz"
|
||||
[ -d "${pixman_version}" ] || tar -xf ${pixman_version}.tar.gz
|
||||
|
||||
mkdir -p build-pixman && cd build-pixman
|
||||
../${pixman_version}/configure \
|
||||
--target=${TARGET} \
|
||||
--prefix=${SYSROOT}/usr \
|
||||
--with-sysroot=${SYSROOT}\
|
||||
CFLAGS="-mcmodel=large -mno-red-zone -O0 -ggdb"
|
||||
|
||||
make
|
||||
make install
|
Loading…
x
Reference in New Issue
Block a user