Compare commits

..

10 Commits

25 changed files with 323 additions and 45 deletions

View File

@@ -12,9 +12,6 @@
"C_Cpp.default.includePath": ["src/kernel/include", "sysroot/usr/include"], "C_Cpp.default.includePath": ["src/kernel/include", "sysroot/usr/include"],
"C_Cpp.default.cStandard": "c17", "C_Cpp.default.cStandard": "c17",
"files.associations": {
"cpu.h": "c"
},
"[c]": { "[c]": {
"editor.tabSize": 2, "editor.tabSize": 2,
}, },

View File

@@ -27,7 +27,7 @@ endif
musllib: $(SYSROOT)/usr/lib/libc.a musllib: $(SYSROOT)/usr/lib/libc.a
$(SYSROOT)/usr/lib/libc.a: $(SYSROOT)/usr/lib/libc.a:
${BUILDROOT}/toolchain/build-musl.sh $(BUILDROOT)/toolchain/ports/musl/build.sh
libmittos: $(SYSROOT)/usr/lib/libmittos.a libmittos: $(SYSROOT)/usr/lib/libmittos.a
$(SYSROOT)/usr/lib/libmittos.a: FORCE $(SYSROOT)/usr/lib/libmittos.a: FORCE
@@ -46,4 +46,7 @@ distclean:
$(MAKE) clean $(MAKE) clean
rm -rf $(SYSROOT) rm -rf $(SYSROOT)
love: FORCE
@echo Not war?
.PHONY: all dist sysroot FORCE .PHONY: all dist sysroot FORCE

32
TODO Normal file
View 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/

View File

@@ -2,6 +2,7 @@
> - [PIC data sheet](http://pdos.csail.mit.edu/6.828/2005/readings/hardware/8259A.pdf) > - [PIC data sheet](http://pdos.csail.mit.edu/6.828/2005/readings/hardware/8259A.pdf)
> - [IOAPIC data sheet](http://web.archive.org/web/20161130153145/http://download.intel.com/design/chipsets/datashts/29056601.pdf) > - [IOAPIC data sheet](http://web.archive.org/web/20161130153145/http://download.intel.com/design/chipsets/datashts/29056601.pdf)
The Advanced Programmable Interrupt Controller (APIC) is not to be confused with (ACPI). The Advanced Programmable Interrupt Controller (APIC) is not to be confused with (ACPI).
It's quite literally an upgrade to the legacy PIC and handles hardware interrupts and IRQs. It's quite literally an upgrade to the legacy PIC and handles hardware interrupts and IRQs.
@@ -16,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. To test that the APIC works, an interrupt can be triggered by writing to the APIC Interrupt Command Registers.
```c ```c
*(uint32_t *)P2V(APIC_BASE + 0x310)) = 0; *(uint32_t *)P2V(APIC_BASE + 0x310) = 0;
*(uint32_t *)P2V(APIC_BASE + 0x300)) = 0x50; *(uint32_t *)P2V(APIC_BASE + 0x300) = 0x50;
``` ```
This should fire interrupt 0x50. This should fire interrupt 0x50.
@@ -104,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. 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`. 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) { static uint64_t ioapic_read_redirection(int irq) {
union iored retval; union iored retval;
retval.l = ioapic_read(0x10 + 2*irq); retval.l = ioapic_read(0x10 + 2*irq);
@@ -170,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: Then set the Timer Mode bit to Periodic and write an interrupt vector to the Local Vector Table entry for the APIC Timer:
```c ```c
*(uint32_t *)P2V(APIC_BASE + 0x3E0)) = 0xB; *(uint32_t *)P2V(APIC_BASE + 0x3E0) = 0xB;
*(uint32_t *)P2V(APIC_BASE + 0x380)) = microseconds * calibration_factor; *(uint32_t *)P2V(APIC_BASE + 0x380) = microseconds * calibration_factor;
*(uint32_t *)P2V(APIC_BASE + 0x320)) = 1<<17 | timer_interrupt; *(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: 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:
@@ -188,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: Setting the divisor, masking its interrupt and setting the initual count will start it counting down immediately:
```c ```c
*(uint32_t *)P2V(APIC_BASE + 0x3E0)) = 0xB; *(uint32_t *)P2V(APIC_BASE + 0x3E0) = 0xB;
*(uint32_t *)P2V(APIC_BASE + 0x380)) = 0xFFFFFFFF; *(uint32_t *)P2V(APIC_BASE + 0x380) = 0xFFFFFFFF;
*(uint32_t *)P2V(APIC_BASE + 0x320)) = 1<<16; *(uint32_t *)P2V(APIC_BASE + 0x320) = 1<<16;
``` ```
For the known interval, I'll use the legacy Programmable Interval Timer - PIT. For the known interval, I'll use the legacy Programmable Interval Timer - PIT.
@@ -227,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: 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 ```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 ## A note about the Red Zone

87
documentation/7 - sse.md Normal file
View 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

View File

@@ -1,7 +1,7 @@
ENTRY(_start) ENTRY(_start)
KERNEL_OFFSET = 0xFFFFFF8000000000; KERNEL_OFFSET = 0xFFFFFF8000000000;
KERNEL_START = 0x10000; KERNEL_START = 0x100000;
SECTIONS SECTIONS
{ {
@@ -10,20 +10,20 @@ SECTIONS
.text : AT(ADDR(.text) - KERNEL_OFFSET) .text : AT(ADDR(.text) - KERNEL_OFFSET)
{ {
*(.multiboot) *(.multiboot)
*(.text) *(.text*)
} }
.rodata : AT(ADDR(.rodata) - KERNEL_OFFSET) .rodata : AT(ADDR(.rodata) - KERNEL_OFFSET)
{ {
*(.rodata*) *(.rodata*)
} }
.data : AT(ADDR(.data) - KERNEL_OFFSET) .data ALIGN(0x1000) : AT(ADDR(.data) - KERNEL_OFFSET)
{ {
*(.data) *(.data*)
} }
.bss : AT(ADDR(.bss) - KERNEL_OFFSET) .bss : AT(ADDR(.bss) - KERNEL_OFFSET)
{ {
*(.COMMON) *(.COMMON)
*(.bss) *(.bss*)
} }
kernel_end = .; kernel_end = .;
} }

View File

@@ -3,6 +3,7 @@
#include <mittos/graphics.h> #include <mittos/graphics.h>
#include <memory.h> #include <memory.h>
#include <cpu.h> #include <cpu.h>
#include <math.h>
extern gfx_context *term_fb; extern gfx_context *term_fb;
extern gfx_context kernel_fb; extern gfx_context kernel_fb;
@@ -11,8 +12,10 @@ int *position = (void *)0x20000;
void thread1() { void thread1() {
int a = 1; int a = 1;
double prev = 0;
gfx_context *ctx = gfx_context *ctx =
framebuffer_make_subcontext(&kernel_fb, 700, 300, 100, 100); framebuffer_make_subcontext(&kernel_fb, 700, 300, 100, 100);
__asm__("sti");
while(1) { while(1) {
putCharacter(term_fb, putCharacter(term_fb,
*position, *position, *position, *position,
@@ -20,14 +23,19 @@ void thread1() {
'0'+(a++%10) '0'+(a++%10)
); );
int s = (current_cpu->timer_ticks/1000)%10; int s = (current_cpu->timer_ticks/1000)%10;
double cur = (double)(current_cpu->timer_ticks/100);
putCharacter(term_fb, putCharacter(term_fb,
0, 0, 0, 0,
RGB(255,255,0), RGB(0,0,0), RGB(255,255,0), RGB(0,0,0),
'0'+(s%10) '0'+(s%10)
); );
flip(term_fb); flip(term_fb);
draw_line(ctx, 0, 100, 50, ((a-1)%100), RGB(0,0,0));
draw_line(ctx, 0, 100, 50, (a%100), RGB(255,0,0)); double angle = cur/3.14*2;
draw_line(ctx, 50, 50 + (int)(50*cos(prev)), 50, 50 + (int)(50*sin(prev)), RGB(0,0,0));
draw_line(ctx, 50, 50 + (int)(50*cos(angle)), 50, 50 + (int)(50*sin(angle)), RGB(255,0,0));
prev = angle;
flip(ctx); flip(ctx);
sched_yield(); sched_yield();
} }
@@ -35,7 +43,17 @@ void thread1() {
void thread2() { void thread2() {
int a = 0; int a = 0;
gfx_context *ctx =
framebuffer_make_subcontext(&kernel_fb, 800, 400, 100, 100);
__asm__("sti");
while(1) { while(1) {
double pos = (double)(current_cpu->timer_ticks/100);
fill_rect(ctx, 0, 0, 100, 100, 0);
for(int i = 0; i < 10000; i++) {
putpixel(ctx, i/100, 50 + (int)(50.0*sin(pos + ((double)i)/1000.0)), RGB(0,0,255));
putpixel(ctx, i/100, 50 + (int)(50.0*cos(pos + ((double)i)/1000.0)), RGB(255,0,0));
}
flip(ctx);
putCharacter(term_fb, putCharacter(term_fb,
*position, *position, *position, *position,
RGB(0,255,255), RGB(0,0,0), RGB(0,255,255), RGB(0,0,0),

View File

@@ -41,8 +41,6 @@ void kmain(uint64_t multiboot_magic, void *multiboot_data) {
cpu_init(); cpu_init();
__asm__("sti");
debug_info("Boot complete\n"); debug_info("Boot complete\n");
@@ -50,6 +48,7 @@ void kmain(uint64_t multiboot_magic, void *multiboot_data) {
irq_unmask(IRQ_PS2_KBD); irq_unmask(IRQ_PS2_KBD);
TEMP_test_scheduler(); TEMP_test_scheduler();
__asm__("sti");
start_scheduler(); start_scheduler();

View File

@@ -27,4 +27,5 @@ void cpu_init() {
apic_init(); apic_init();
ioapic_init(); ioapic_init();
timer_init(); timer_init();
sse_init();
} }

30
src/kernel/cpu/sse.S Normal file
View File

@@ -0,0 +1,30 @@
.intel_syntax noprefix
.global sse_init
sse_init:
//; Enable bits 9 and 10 in cr4
//; 9: Enable SSE instructions
//; 10: Enable SSE exceptions
mov rax, cr4
or rax, 1<<9 | 1<<10
mov cr4, rax
//; Set bit 1 and unset bit 2 in cr0
//; 1: Coprocessor monitoring
//; 2: Coprocessor emulation
mov rax, cr0
or rax, 1<<1
and rax, ~(1<<2)
mov cr0, rax
ret
.global sse_save
sse_save:
fxsave [rdi]
ret
.global sse_restore
sse_restore:
fxrstor [rdi]
ret

View File

@@ -69,6 +69,7 @@ volatile int ctr = 0;
registers *apic_timer_handler(registers *r) { registers *apic_timer_handler(registers *r) {
current_cpu->timer_ticks++; current_cpu->timer_ticks++;
irq_ack(); irq_ack();
// k_sched_yield();
return r; return r;
} }

View File

@@ -98,4 +98,9 @@ void irq_unmask(int irq);
void ioapic_init(); void ioapic_init();
// cpu/timer.c // cpu/timer.c
void timer_init(); void timer_init();
// cpu/sse.S
void sse_init();
void sse_save(void *addr);
void sse_restore(void *addr);

View File

@@ -7,6 +7,7 @@ struct process {
uint64_t state; uint64_t state;
uint64_t P4; uint64_t P4;
struct process *q_next; struct process *q_next;
void *sse;
uint8_t stack[]; uint8_t stack[];
}; };

View File

@@ -1,5 +1,7 @@
#include <memory.h> #include <memory.h>
#include <debug.h> #include <debug.h>
#include <sys/mman.h>
#include <string.h>
static long _brk = KERNEL_BRK0; static long _brk = KERNEL_BRK0;
static long _mmap = KERNEL_MMAP; static long _mmap = KERNEL_MMAP;
@@ -33,14 +35,22 @@ long k_mmap(
if(fd != -1) if(fd != -1)
PANIC("Unknown mmap request\n"); PANIC("Unknown mmap request\n");
long retval = _mmap; long pos = (flags & MAP_FIXED) ? addr : _mmap;
while(length > 0) { long retval = pos;
uint64_t p;
while(length >= 0) {
p = pmm_alloc();
vmm_set_page(kernel_P4, vmm_set_page(kernel_P4,
_mmap, pmm_alloc(), pos, p,
PAGE_GLOBAL | PAGE_WRITE | PAGE_PRESENT PAGE_GLOBAL | PAGE_WRITE | PAGE_PRESENT
); );
_mmap += PAGE_SIZE; if(flags & MAP_ANONYMOUS) {
memset((void *)pos, 0, PAGE_SIZE);
}
pos += PAGE_SIZE;
length -= PAGE_SIZE; length -= PAGE_SIZE;
} }
if(!(flags & MAP_FIXED))
_mmap = pos;
return retval; return retval;
} }

View File

@@ -1,6 +1,7 @@
#include <stdint.h> #include <stdint.h>
#include <proc.h> #include <proc.h>
#include <memory.h> #include <memory.h>
#include <stdlib.h>
struct swtch_stack { struct swtch_stack {
uint64_t RBP; uint64_t RBP;
@@ -24,6 +25,10 @@ struct process *new_process(void (*function)(void)) {
p->q_next = 0; p->q_next = 0;
p->P4 = new_P4(); p->P4 = new_P4();
// Storage for SSE registers must be 16 byte aligned
void *sse = malloc(512+15);
p->sse = (void *) (((uintptr_t)sse + 15) & ~0xF);
struct swtch_stack *stck = p->stack_ptr; struct swtch_stack *stck = p->stack_ptr;
stck->RBP = (uint64_t)&stck->RBP2; stck->RBP = (uint64_t)&stck->RBP2;
stck->ret = (uint64_t)function; stck->ret = (uint64_t)function;

View File

@@ -32,8 +32,11 @@ void scheduler() {
current_proc = new; current_proc = new;
write_cr3(new->P4); write_cr3(new->P4);
sse_restore(current_proc->sse);
switch_stack(&scheduler_proc->stack_ptr, &new->stack_ptr); switch_stack(&scheduler_proc->stack_ptr, &new->stack_ptr);
sse_save(current_proc->sse);
scheduler_insert(current_proc); scheduler_insert(current_proc);
current_proc = 0; current_proc = 0;
} }

View File

@@ -19,7 +19,7 @@ libmittos.a: $(OBJ)
graphics/graphics.o: graphics/u_vga16.termfont.inc graphics/graphics.o: graphics/u_vga16.termfont.inc
graphics/u_vga16.termfont.inc: graphics/u_vga16.termfont.inc:
${BUILDROOT}/toolchain/build-uni_vga.sh ${BUILDROOT}/toolchain/ports/uni_vga/build.sh
# Automatic dependency tracking # Automatic dependency tracking
DEP := $(OBJ:.o=.d) DEP := $(OBJ:.o=.d)
@@ -31,7 +31,7 @@ $(OBJ): CPPFLAGS += $(DEPFLAGS)
# Installation # Installation
DESTDIR ?= $(BUILDROOT)/sysroot DESTDIR ?= $(BUILDROOT)/sysroot
LIBDIR := $(DESTDIR)/usr/lib LIBDIR := $(DESTDIR)/usr/lib
INCDIR := $(DESTDIR)/usr/include/mittos INCDIR := $(DESTDIR)/usr/include
$(LIBDIR)/libmittos.a: libmittos.a $(LIBDIR)/libmittos.a: libmittos.a
install -D $< $@ install -D $< $@

View File

@@ -1,7 +1,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <graphics.h> #include <mittos/graphics.h>
#define incptr(p, n) ((void *)(((uintptr_t)(p)) + (n))) #define incptr(p, n) ((void *)(((uintptr_t)(p)) + (n)))
@@ -27,23 +27,32 @@ void draw_line(
uint64_t y0, uint64_t y1, uint64_t y0, uint64_t y1,
uint32_t clr uint32_t clr
) { ) {
// https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
int64_t dx = x1 > x0 ? x1 - x0 : x0 - x1; int64_t dx = x1 > x0 ? x1 - x0 : x0 - x1;
int sx = x0 < x1 ? 1 : -1;
int64_t dy = y1 > y0 ? y1 - y0 : y0 - y1; int64_t dy = y1 > y0 ? y1 - y0 : y0 - y1;
int sx = x1 > x0 ? 1 : -1; dy = -dy;
int sy = y1 > y0 ? 1 : -1; int sy = y0 < y1 ? 1 : -1;
uint64_t x = x0, y = y0; int64_t err = dx + dy;
int64_t diff = dx - dy;
uint32_t *fb = (uint32_t *)ctx->buffer; uint32_t *fb = (uint32_t *)ctx->buffer;
while(1) { while(1) {
fb[PXL(ctx, x, y)] = clr; if(0 < x0 && x0 < ctx->width &&
if(x == x1 && y == y1) break; 0 < y0 && y0 < ctx->height)
fb[PXL(ctx, x0, y0)] = clr;
if(x0 == x1 && y0 == y1) break;
if((2*diff) > -dy) { int64_t e2 = 2*err;
diff -= dy; if(e2 >= dy) {
x += sx; if(x0 == x1) break;
} else { err += dy;
diff += dx; x0 += sx;
y += sy; }
if(e2 <= dx) {
if(y0 == y1) break;
err += dx;
y0 += sy;
} }
} }
} }

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
typedef struct { typedef struct {
uint32_t width; uint32_t width;

View File

@@ -58,7 +58,5 @@ mkdir gcc-build && cd gcc-build
make all-gcc all-target-libgcc -j 4 make all-gcc all-target-libgcc -j 4
make install-gcc install-target-libgcc make install-gcc install-target-libgcc
apk del build-base
cd / cd /
rm -rf /opt rm -rf /opt

View 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

View 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

View 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