mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-07-11 23:39:20 +00:00
Support i386
This commit is contained in:
327
Architecture/i386/ArithmeticOperations.c
Normal file
327
Architecture/i386/ArithmeticOperations.c
Normal file
@ -0,0 +1,327 @@
|
||||
/* Source: https://github.com/glitchub/arith64 */
|
||||
#define arith64_u64 unsigned long long int
|
||||
#define arith64_s64 signed long long int
|
||||
#define arith64_u32 unsigned int
|
||||
#define arith64_s32 int
|
||||
|
||||
typedef union
|
||||
{
|
||||
arith64_u64 u64;
|
||||
arith64_s64 s64;
|
||||
struct
|
||||
{
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
arith64_u32 hi;
|
||||
arith64_u32 lo;
|
||||
#else
|
||||
arith64_u32 lo;
|
||||
arith64_u32 hi;
|
||||
#endif
|
||||
} u32;
|
||||
struct
|
||||
{
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
arith64_s32 hi;
|
||||
arith64_s32 lo;
|
||||
#else
|
||||
arith64_s32 lo;
|
||||
arith64_s32 hi;
|
||||
#endif
|
||||
} s32;
|
||||
} arith64_word;
|
||||
|
||||
#define arith64_hi(n) (arith64_word){.u64 = n}.u32.hi
|
||||
#define arith64_lo(n) (arith64_word){.u64 = n}.u32.lo
|
||||
#define arith64_neg(a, b) (((a) ^ ((((arith64_s64)(b)) >= 0) - 1)) + (((arith64_s64)(b)) < 0))
|
||||
#define arith64_abs(a) arith64_neg(a, a)
|
||||
|
||||
arith64_s64 __absvdi2(arith64_s64 a)
|
||||
{
|
||||
return arith64_abs(a);
|
||||
}
|
||||
|
||||
arith64_s64 __ashldi3(arith64_s64 a, int b)
|
||||
{
|
||||
arith64_word w = {.s64 = a};
|
||||
|
||||
b &= 63;
|
||||
|
||||
if (b >= 32)
|
||||
{
|
||||
w.u32.hi = w.u32.lo << (b - 32);
|
||||
w.u32.lo = 0;
|
||||
}
|
||||
else if (b)
|
||||
{
|
||||
w.u32.hi = (w.u32.lo >> (32 - b)) | (w.u32.hi << b);
|
||||
w.u32.lo <<= b;
|
||||
}
|
||||
return w.s64;
|
||||
}
|
||||
|
||||
arith64_s64 __ashrdi3(arith64_s64 a, int b)
|
||||
{
|
||||
arith64_word w = {.s64 = a};
|
||||
|
||||
b &= 63;
|
||||
|
||||
if (b >= 32)
|
||||
{
|
||||
w.s32.lo = w.s32.hi >> (b - 32);
|
||||
w.s32.hi >>= 31; // 0xFFFFFFFF or 0
|
||||
}
|
||||
else if (b)
|
||||
{
|
||||
w.u32.lo = (w.u32.hi << (32 - b)) | (w.u32.lo >> b);
|
||||
w.s32.hi >>= b;
|
||||
}
|
||||
return w.s64;
|
||||
}
|
||||
|
||||
int __clzsi2(arith64_u32 a)
|
||||
{
|
||||
int b, n = 0;
|
||||
b = !(a & 0xffff0000) << 4;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xff000000) << 3;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xf0000000) << 2;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xc0000000) << 1;
|
||||
n += b;
|
||||
a <<= b;
|
||||
return n + !(a & 0x80000000);
|
||||
}
|
||||
|
||||
int __clzdi2(arith64_u64 a)
|
||||
{
|
||||
int b, n = 0;
|
||||
b = !(a & 0xffffffff00000000ULL) << 5;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xffff000000000000ULL) << 4;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xff00000000000000ULL) << 3;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xf000000000000000ULL) << 2;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xc000000000000000ULL) << 1;
|
||||
n += b;
|
||||
a <<= b;
|
||||
return n + !(a & 0x8000000000000000ULL);
|
||||
}
|
||||
|
||||
int __ctzsi2(arith64_u32 a)
|
||||
{
|
||||
int b, n = 0;
|
||||
b = !(a & 0x0000ffff) << 4;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x000000ff) << 3;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x0000000f) << 2;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x00000003) << 1;
|
||||
n += b;
|
||||
a >>= b;
|
||||
return n + !(a & 0x00000001);
|
||||
}
|
||||
|
||||
int __ctzdi2(arith64_u64 a)
|
||||
{
|
||||
int b, n = 0;
|
||||
b = !(a & 0x00000000ffffffffULL) << 5;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x000000000000ffffULL) << 4;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x00000000000000ffULL) << 3;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x000000000000000fULL) << 2;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x0000000000000003ULL) << 1;
|
||||
n += b;
|
||||
a >>= b;
|
||||
return n + !(a & 0x0000000000000001ULL);
|
||||
}
|
||||
|
||||
arith64_u64 __divmoddi4(arith64_u64 a, arith64_u64 b, arith64_u64 *c)
|
||||
{
|
||||
if (b > a)
|
||||
{
|
||||
if (c)
|
||||
*c = a;
|
||||
return 0;
|
||||
}
|
||||
if (!arith64_hi(b))
|
||||
{
|
||||
if (b == 0)
|
||||
{
|
||||
volatile char x = 0;
|
||||
x = 1 / x;
|
||||
}
|
||||
if (b == 1)
|
||||
{
|
||||
if (c)
|
||||
*c = 0;
|
||||
return a;
|
||||
}
|
||||
if (!arith64_hi(a))
|
||||
{
|
||||
if (c)
|
||||
*c = arith64_lo(a) % arith64_lo(b);
|
||||
return arith64_lo(a) / arith64_lo(b);
|
||||
}
|
||||
}
|
||||
|
||||
char bits = __clzdi2(b) - __clzdi2(a) + 1;
|
||||
arith64_u64 rem = a >> bits;
|
||||
a <<= 64 - bits;
|
||||
arith64_u64 wrap = 0;
|
||||
while (bits-- > 0)
|
||||
{
|
||||
rem = (rem << 1) | (a >> 63);
|
||||
a = (a << 1) | (wrap & 1);
|
||||
wrap = ((arith64_s64)(b - rem - 1) >> 63);
|
||||
rem -= b & wrap;
|
||||
}
|
||||
if (c)
|
||||
*c = rem;
|
||||
return (a << 1) | (wrap & 1);
|
||||
}
|
||||
|
||||
arith64_s64 __divdi3(arith64_s64 a, arith64_s64 b)
|
||||
{
|
||||
arith64_u64 q = __divmoddi4(arith64_abs(a), arith64_abs(b), (void *)0);
|
||||
return arith64_neg(q, a ^ b);
|
||||
}
|
||||
|
||||
int __ffsdi2(arith64_u64 a) { return a ? __ctzdi2(a) + 1 : 0; }
|
||||
|
||||
arith64_u64 __lshrdi3(arith64_u64 a, int b)
|
||||
{
|
||||
arith64_word w = {.u64 = a};
|
||||
|
||||
b &= 63;
|
||||
|
||||
if (b >= 32)
|
||||
{
|
||||
w.u32.lo = w.u32.hi >> (b - 32);
|
||||
w.u32.hi = 0;
|
||||
}
|
||||
else if (b)
|
||||
{
|
||||
w.u32.lo = (w.u32.hi << (32 - b)) | (w.u32.lo >> b);
|
||||
w.u32.hi >>= b;
|
||||
}
|
||||
return w.u64;
|
||||
}
|
||||
|
||||
arith64_s64 __moddi3(arith64_s64 a, arith64_s64 b)
|
||||
{
|
||||
arith64_u64 r;
|
||||
__divmoddi4(arith64_abs(a), arith64_abs(b), &r);
|
||||
return arith64_neg(r, a);
|
||||
}
|
||||
|
||||
int __popcountsi2(arith64_u32 a)
|
||||
{
|
||||
|
||||
a = a - ((a >> 1) & 0x55555555);
|
||||
a = ((a >> 2) & 0x33333333) + (a & 0x33333333);
|
||||
a = (a + (a >> 4)) & 0x0F0F0F0F;
|
||||
a = (a + (a >> 16));
|
||||
|
||||
return (a + (a >> 8)) & 63;
|
||||
}
|
||||
|
||||
int __popcountdi2(arith64_u64 a)
|
||||
{
|
||||
|
||||
a = a - ((a >> 1) & 0x5555555555555555ULL);
|
||||
a = ((a >> 2) & 0x3333333333333333ULL) + (a & 0x3333333333333333ULL);
|
||||
a = (a + (a >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
|
||||
a = (a + (a >> 32));
|
||||
a = (a + (a >> 16));
|
||||
|
||||
return (a + (a >> 8)) & 127;
|
||||
}
|
||||
|
||||
arith64_u64 __udivdi3(arith64_u64 a, arith64_u64 b) { return __divmoddi4(a, b, (void *)0); }
|
||||
|
||||
arith64_u64 __umoddi3(arith64_u64 a, arith64_u64 b)
|
||||
{
|
||||
arith64_u64 r;
|
||||
__divmoddi4(a, b, &r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Good documentation: https://splichal.eu/scripts/sphinx/gccint/_build/html/the-gcc-low-level-runtime-library/routines-for-floating-point-emulation.html */
|
||||
|
||||
double __adddf3(double a, double b) { return a + b; }
|
||||
double __muldf3(double a, double b) { return a * b; }
|
||||
double __floatsidf(int i) { return (double)i; }
|
||||
int __ltdf2(double a, double b) { return a < b; }
|
||||
int __gtdf2(double a, double b) { return a > b; }
|
||||
int __nedf2(double a, double b) { return a != b; }
|
||||
int __eqdf2(double a, double b) { return a == b; }
|
||||
double __floatdidf(long i) { return (double)i; }
|
||||
double __divdf3(double a, double b) { return a / b; }
|
||||
double __subdf3(double a, double b) { return a - b; }
|
||||
int __gedf2(double a, double b) { return a >= b; }
|
||||
int __fixdfsi(double a) { return (int)a; }
|
||||
long __fixdfdi(double a) { return (long)a; }
|
||||
int __ledf2(double a, double b) { return a <= b; }
|
||||
|
||||
/* FIXME: Check if these functions are implemented correctly */
|
||||
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef struct
|
||||
{
|
||||
uint64_t value;
|
||||
} atomic_uint64_t;
|
||||
|
||||
uint64_t __atomic_load_8(const atomic_uint64_t *p)
|
||||
{
|
||||
uint64_t value;
|
||||
__asm__ volatile("lock cmpxchg8b %1"
|
||||
: "=A"(value)
|
||||
: "m"(*p)
|
||||
: "memory");
|
||||
return value;
|
||||
}
|
||||
|
||||
void __atomic_store_8(atomic_uint64_t *p, uint64_t value)
|
||||
{
|
||||
__asm__ volatile("lock cmpxchg8b %0"
|
||||
: "=m"(p->value)
|
||||
: "a"((uint32_t)value), "d"((uint32_t)(value >> 32)), "m"(*p)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
/* FIXME: __fixsfsi is not implemented correctly(?) */
|
||||
int __fixsfsi(float a) { return (int)a; }
|
||||
|
||||
int __ltsf2(float a, float b) { return a < b; }
|
||||
int __eqsf2(float a, float b) { return a == b; }
|
||||
float __divsf3(float a, float b) { return a / b; }
|
||||
double __extendsfdf2(float a) { return (double)a; }
|
||||
float __truncdfsf2(double a) { return (float)a; }
|
||||
float __subsf3(float a, float b) { return a - b; }
|
||||
float __floatsisf(int a) { return (float)a; }
|
||||
int __fixunssfsi(float a) { return (int)a; }
|
||||
float __mulsf3(float a, float b) { return a * b; }
|
||||
float __addsf3(float a, float b) { return a + b; }
|
54
Architecture/i386/Bootstrap/MB2.asm
Normal file
54
Architecture/i386/Bootstrap/MB2.asm
Normal file
@ -0,0 +1,54 @@
|
||||
; https://wiki.osdev.org/Higher_Half_x86_Bare_Bones
|
||||
; https://wiki.osdev.org/Higher_Half_x86_Bare_Bones_(Backup)
|
||||
|
||||
KERNEL_VIRTUAL_BASE equ 0xC0000000 ; 3GB
|
||||
KERNEL_STACK_SIZE equ 0x4000 ; 16KB
|
||||
|
||||
extern Multiboot2Entry
|
||||
extern BootPageTable
|
||||
global MB2_start
|
||||
|
||||
section .text
|
||||
MB2_start:
|
||||
cli
|
||||
mov word [0xb8F00], 0x072E ; .
|
||||
|
||||
mov ecx, (BootPageTable - KERNEL_VIRTUAL_BASE)
|
||||
mov cr3, ecx
|
||||
|
||||
mov word [0xb8F02], 0x072E ; .
|
||||
|
||||
mov ecx, cr4
|
||||
or ecx, 0x00000010 ; Set PSE in CR4
|
||||
mov cr4, ecx
|
||||
|
||||
mov word [0xb8F04], 0x072E ; .
|
||||
|
||||
mov ecx, cr0
|
||||
or ecx, 0x80000000 ; Set PG in CR0
|
||||
mov cr0, ecx
|
||||
|
||||
mov word [0xb8F06], 0x072E ; .
|
||||
|
||||
lea ecx, [HigherHalfStart]
|
||||
jmp ecx
|
||||
|
||||
HigherHalfStart:
|
||||
mov word [0xb8F08], 0x072E ; .
|
||||
mov dword [BootPageTable], 0
|
||||
invlpg [0]
|
||||
|
||||
mov esp, KernelStack + KERNEL_STACK_SIZE
|
||||
|
||||
push eax ; Multiboot2 Magic
|
||||
add ebx, KERNEL_VIRTUAL_BASE
|
||||
push ebx ; Multiboot2 Header
|
||||
call Multiboot2Entry
|
||||
Loop:
|
||||
hlt
|
||||
jmp Loop
|
||||
|
||||
section .bss
|
||||
align 16
|
||||
KernelStack:
|
||||
resb KERNEL_STACK_SIZE
|
41
Architecture/i386/Bootstrap/MB2Header.asm
Normal file
41
Architecture/i386/Bootstrap/MB2Header.asm
Normal file
@ -0,0 +1,41 @@
|
||||
section .multiboot2
|
||||
align 4096
|
||||
HEADER_START:
|
||||
dd 0xE85250D6
|
||||
dd 0
|
||||
dd (HEADER_END - HEADER_START)
|
||||
dd 0x100000000 - (HEADER_END - HEADER_START) - 0 - 0xE85250D6
|
||||
align 8
|
||||
MB2_INFO_REQUEST_TAG_START:
|
||||
dw 1
|
||||
dw 0
|
||||
dd MB2_INFO_REQUEST_TAG_END - MB2_INFO_REQUEST_TAG_START
|
||||
dd 1 ; Command Line
|
||||
dd 2 ; Boot Loader Name
|
||||
dd 3 ; Module
|
||||
dd 4 ; Basic Memory Information
|
||||
dd 5 ; BIOS Boot Device
|
||||
dd 6 ; Memory Map
|
||||
dd 7 ; VBE
|
||||
dd 8 ; Framebuffer
|
||||
dd 9 ; ELF Sections
|
||||
dd 10 ; APM Table
|
||||
dd 11 ; EFI 32-bit System Table Pointer
|
||||
dd 12 ; EFI 64-bit System Table Pointer
|
||||
; dd 13 ; SMBIOS
|
||||
dd 14 ; ACPI Old
|
||||
dd 15 ; ACPI New
|
||||
dd 16 ; Network
|
||||
dd 17 ; EFI Memory Map
|
||||
dd 18 ; EFI Boot Services Notifier
|
||||
dd 19 ; EFI 32-bit Image Handle Pointer
|
||||
dd 20 ; EFI 64-bit Image Handle Pointer
|
||||
dd 21 ; Load Base Address
|
||||
MB2_INFO_REQUEST_TAG_END:
|
||||
align 8
|
||||
MB2_TAG_START:
|
||||
dw 0
|
||||
dw 0
|
||||
dd MB2_TAG_END - MB2_TAG_START
|
||||
MB2_TAG_END:
|
||||
HEADER_END:
|
13
Architecture/i386/Bootstrap/MB2PageTable.asm
Normal file
13
Architecture/i386/Bootstrap/MB2PageTable.asm
Normal file
@ -0,0 +1,13 @@
|
||||
KERNEL_VIRTUAL_BASE equ 0xC0000000 ; 3GB
|
||||
KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22) ; 768
|
||||
|
||||
section .data
|
||||
global BootPageTable
|
||||
align 0x1000
|
||||
BootPageTable:
|
||||
dd 0x00000083
|
||||
dd 0x00000083
|
||||
times (KERNEL_PAGE_NUMBER - 2) dd 0
|
||||
dd 0x00000083
|
||||
dd 0x00000083
|
||||
times (1024 - KERNEL_PAGE_NUMBER - 2) dd 0
|
339
Architecture/i386/Bootstrap/Multiboot2.cpp
Normal file
339
Architecture/i386/Bootstrap/Multiboot2.cpp
Normal file
@ -0,0 +1,339 @@
|
||||
#include <types.h>
|
||||
|
||||
#include <boot/protocols/multiboot2.h>
|
||||
#include <memory.hpp>
|
||||
#include <io.h>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
|
||||
BootInfo mb2binfo;
|
||||
|
||||
enum VideoType
|
||||
{
|
||||
VIDEO_TYPE_NONE = 0x00,
|
||||
VIDEO_TYPE_COLOUR = 0x20,
|
||||
VIDEO_TYPE_MONOCHROME = 0x30,
|
||||
};
|
||||
|
||||
uint16_t GetBiosAreaHardware()
|
||||
{
|
||||
const uint16_t *BIOSDataAreaDetectedHardware = (const uint16_t *)0x410;
|
||||
return *BIOSDataAreaDetectedHardware;
|
||||
}
|
||||
|
||||
enum VideoType GetVideoType() { return (enum VideoType)(GetBiosAreaHardware() & 0x30); }
|
||||
|
||||
void GetSMBIOS()
|
||||
{
|
||||
unsigned char *SMBIOSAddress = (unsigned char *)0xF0000;
|
||||
while ((unsigned int)(unsigned long)SMBIOSAddress < 0x100000)
|
||||
{
|
||||
if (SMBIOSAddress[0] == '_' &&
|
||||
SMBIOSAddress[1] == 'S' &&
|
||||
SMBIOSAddress[2] == 'M' &&
|
||||
SMBIOSAddress[3] == '_')
|
||||
{
|
||||
unsigned char Checksum = 0;
|
||||
int Length = SMBIOSAddress[5];
|
||||
for (int i = 0; i < Length; i++)
|
||||
Checksum += SMBIOSAddress[i];
|
||||
|
||||
if (Checksum == 0)
|
||||
break;
|
||||
}
|
||||
SMBIOSAddress += 16;
|
||||
}
|
||||
|
||||
if ((unsigned int)(unsigned long)SMBIOSAddress == 0x100000)
|
||||
{
|
||||
// No SMBIOS found
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessMB2(unsigned long Info)
|
||||
{
|
||||
uint8_t *VideoBuffer = (uint8_t *)0xB8F00 + 0xC0000000;
|
||||
int pos = 0;
|
||||
auto InfoAddress = Info;
|
||||
for (auto Tag = (struct multiboot_tag *)((uint8_t *)InfoAddress + 8);
|
||||
;
|
||||
Tag = (struct multiboot_tag *)((multiboot_uint8_t *)Tag + ((Tag->size + 7) & ~7)))
|
||||
{
|
||||
VideoBuffer[pos++] = '.';
|
||||
VideoBuffer[pos++] = 0x2;
|
||||
|
||||
if (Tag->type == MULTIBOOT_TAG_TYPE_END)
|
||||
{
|
||||
debug("End of multiboot2 tags");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (Tag->type)
|
||||
{
|
||||
case MULTIBOOT_TAG_TYPE_CMDLINE:
|
||||
{
|
||||
strncpy(mb2binfo.Kernel.CommandLine,
|
||||
((multiboot_tag_string *)Tag)->string,
|
||||
strlen(((multiboot_tag_string *)Tag)->string));
|
||||
debug("Kernel command line: %s", mb2binfo.Kernel.CommandLine);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
|
||||
{
|
||||
strncpy(mb2binfo.Bootloader.Name,
|
||||
((multiboot_tag_string *)Tag)->string,
|
||||
strlen(((multiboot_tag_string *)Tag)->string));
|
||||
debug("Bootloader name: %s", mb2binfo.Bootloader.Name);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_MODULE:
|
||||
{
|
||||
multiboot_tag_module *module = (multiboot_tag_module *)Tag;
|
||||
static int module_count = 0;
|
||||
mb2binfo.Modules[module_count++].Address = (void *)module->mod_start;
|
||||
mb2binfo.Modules[module_count++].Size = module->size;
|
||||
strncpy(mb2binfo.Modules[module_count++].Path, "(null)", 6);
|
||||
strncpy(mb2binfo.Modules[module_count++].CommandLine, module->cmdline,
|
||||
strlen(module->cmdline));
|
||||
debug("Module: %s", mb2binfo.Modules[module_count++].Path);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
|
||||
{
|
||||
multiboot_tag_basic_meminfo *meminfo = (multiboot_tag_basic_meminfo *)Tag;
|
||||
fixme("basic_meminfo->[mem_lower: %#x, mem_upper: %#x]",
|
||||
meminfo->mem_lower, meminfo->mem_upper);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_BOOTDEV:
|
||||
{
|
||||
multiboot_tag_bootdev *bootdev = (multiboot_tag_bootdev *)Tag;
|
||||
fixme("bootdev->[biosdev: %#x, slice: %#x, part: %#x]",
|
||||
bootdev->biosdev, bootdev->slice, bootdev->part);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_MMAP:
|
||||
{
|
||||
multiboot_tag_mmap *mmap = (multiboot_tag_mmap *)Tag;
|
||||
uint32_t EntryCount = mmap->size / sizeof(multiboot_mmap_entry);
|
||||
mb2binfo.Memory.Entries = EntryCount;
|
||||
for (uint32_t i = 0; i < EntryCount; i++)
|
||||
{
|
||||
if (EntryCount > MAX_MEMORY_ENTRIES)
|
||||
{
|
||||
warn("Too many memory entries, skipping the rest...");
|
||||
break;
|
||||
}
|
||||
multiboot_mmap_entry entry = mmap->entries[i];
|
||||
mb2binfo.Memory.Size += entry.len;
|
||||
switch (entry.type)
|
||||
{
|
||||
case MULTIBOOT_MEMORY_AVAILABLE:
|
||||
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
|
||||
mb2binfo.Memory.Entry[i].Length = entry.len;
|
||||
mb2binfo.Memory.Entry[i].Type = Usable;
|
||||
break;
|
||||
case MULTIBOOT_MEMORY_RESERVED:
|
||||
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
|
||||
mb2binfo.Memory.Entry[i].Length = entry.len;
|
||||
mb2binfo.Memory.Entry[i].Type = Reserved;
|
||||
break;
|
||||
case MULTIBOOT_MEMORY_ACPI_RECLAIMABLE:
|
||||
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
|
||||
mb2binfo.Memory.Entry[i].Length = entry.len;
|
||||
mb2binfo.Memory.Entry[i].Type = ACPIReclaimable;
|
||||
break;
|
||||
case MULTIBOOT_MEMORY_NVS:
|
||||
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
|
||||
mb2binfo.Memory.Entry[i].Length = entry.len;
|
||||
mb2binfo.Memory.Entry[i].Type = ACPINVS;
|
||||
break;
|
||||
case MULTIBOOT_MEMORY_BADRAM:
|
||||
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
|
||||
mb2binfo.Memory.Entry[i].Length = entry.len;
|
||||
mb2binfo.Memory.Entry[i].Type = BadMemory;
|
||||
break;
|
||||
default:
|
||||
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
|
||||
mb2binfo.Memory.Entry[i].Length = entry.len;
|
||||
mb2binfo.Memory.Entry[i].Type = Unknown;
|
||||
break;
|
||||
}
|
||||
debug("Memory entry: [BaseAddress: %#x, Length: %#x, Type: %d]",
|
||||
mb2binfo.Memory.Entry[i].BaseAddress,
|
||||
mb2binfo.Memory.Entry[i].Length,
|
||||
mb2binfo.Memory.Entry[i].Type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_VBE:
|
||||
{
|
||||
multiboot_tag_vbe *vbe = (multiboot_tag_vbe *)Tag;
|
||||
fixme("vbe->[vbe_mode: %#x, vbe_interface_seg: %#x, vbe_interface_off: %#x, vbe_interface_len: %#x]",
|
||||
vbe->vbe_mode, vbe->vbe_interface_seg, vbe->vbe_interface_off, vbe->vbe_interface_len);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
|
||||
{
|
||||
multiboot_tag_framebuffer *fb = (multiboot_tag_framebuffer *)Tag;
|
||||
static int fb_count = 0;
|
||||
mb2binfo.Framebuffer[fb_count].BaseAddress = (void *)fb->common.framebuffer_addr;
|
||||
mb2binfo.Framebuffer[fb_count].Width = fb->common.framebuffer_width;
|
||||
mb2binfo.Framebuffer[fb_count].Height = fb->common.framebuffer_height;
|
||||
mb2binfo.Framebuffer[fb_count].Pitch = fb->common.framebuffer_pitch;
|
||||
mb2binfo.Framebuffer[fb_count].BitsPerPixel = fb->common.framebuffer_bpp;
|
||||
mb2binfo.Framebuffer[fb_count].MemoryModel = fb->common.framebuffer_type;
|
||||
switch (fb->common.framebuffer_type)
|
||||
{
|
||||
case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
|
||||
{
|
||||
fixme("indexed");
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
|
||||
{
|
||||
mb2binfo.Framebuffer[fb_count].RedMaskSize = fb->framebuffer_red_mask_size;
|
||||
mb2binfo.Framebuffer[fb_count].RedMaskShift = fb->framebuffer_red_field_position;
|
||||
mb2binfo.Framebuffer[fb_count].GreenMaskSize = fb->framebuffer_green_mask_size;
|
||||
mb2binfo.Framebuffer[fb_count].GreenMaskShift = fb->framebuffer_green_field_position;
|
||||
mb2binfo.Framebuffer[fb_count].BlueMaskSize = fb->framebuffer_blue_mask_size;
|
||||
mb2binfo.Framebuffer[fb_count].BlueMaskShift = fb->framebuffer_blue_field_position;
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
|
||||
{
|
||||
fixme("ega_text");
|
||||
break;
|
||||
}
|
||||
}
|
||||
debug("Framebuffer %d: %dx%d %d bpp", Tag, fb->common.framebuffer_width, fb->common.framebuffer_height, fb->common.framebuffer_bpp);
|
||||
debug("More info:\nAddress: %p\nPitch: %lld\nMemoryModel: %d\nRedMaskSize: %d\nRedMaskShift: %d\nGreenMaskSize: %d\nGreenMaskShift: %d\nBlueMaskSize: %d\nBlueMaskShift: %d",
|
||||
fb->common.framebuffer_addr, fb->common.framebuffer_pitch, fb->common.framebuffer_type,
|
||||
fb->framebuffer_red_mask_size, fb->framebuffer_red_field_position, fb->framebuffer_green_mask_size,
|
||||
fb->framebuffer_green_field_position, fb->framebuffer_blue_mask_size, fb->framebuffer_blue_field_position);
|
||||
fb_count++;
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
|
||||
{
|
||||
multiboot_tag_elf_sections *elf = (multiboot_tag_elf_sections *)Tag;
|
||||
fixme("elf_sections->[num=%d, size=%d, entsize=%d, shndx=%d]",
|
||||
elf->num, elf->size, elf->entsize, elf->shndx);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_APM:
|
||||
{
|
||||
multiboot_tag_apm *apm = (multiboot_tag_apm *)Tag;
|
||||
fixme("apm->[version: %d, cseg: %d, offset: %d, cseg_16: %d, dseg: %d, flags: %d, cseg_len: %d, cseg_16_len: %d, dseg_len: %d]",
|
||||
apm->version, apm->cseg, apm->offset, apm->cseg_16, apm->dseg, apm->flags, apm->cseg_len, apm->cseg_16_len, apm->dseg_len);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_EFI32:
|
||||
{
|
||||
multiboot_tag_efi32 *efi32 = (multiboot_tag_efi32 *)Tag;
|
||||
fixme("efi32->[pointer: %p, size: %d]", efi32->pointer, efi32->size);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_EFI64:
|
||||
{
|
||||
multiboot_tag_efi64 *efi64 = (multiboot_tag_efi64 *)Tag;
|
||||
fixme("efi64->[pointer: %p, size: %d]", efi64->pointer, efi64->size);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_SMBIOS:
|
||||
{
|
||||
multiboot_tag_smbios *smbios = (multiboot_tag_smbios *)Tag;
|
||||
fixme("smbios->[major: %d, minor: %d]", smbios->major, smbios->minor);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_ACPI_OLD:
|
||||
{
|
||||
mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_old_acpi *)Tag)->rsdp;
|
||||
debug("OLD ACPI RSDP: %p", mb2binfo.RSDP);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_ACPI_NEW:
|
||||
{
|
||||
mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_new_acpi *)Tag)->rsdp;
|
||||
debug("NEW ACPI RSDP: %p", mb2binfo.RSDP);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_NETWORK:
|
||||
{
|
||||
multiboot_tag_network *net = (multiboot_tag_network *)Tag;
|
||||
fixme("network->[dhcpack: %p]", net->dhcpack);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_EFI_MMAP:
|
||||
{
|
||||
multiboot_tag_efi_mmap *efi_mmap = (multiboot_tag_efi_mmap *)Tag;
|
||||
fixme("efi_mmap->[descr_size: %d, descr_vers: %d, efi_mmap: %p]",
|
||||
efi_mmap->descr_size, efi_mmap->descr_vers, efi_mmap->efi_mmap);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_EFI_BS:
|
||||
{
|
||||
fixme("efi_bs->[%p] (unknown structure)", Tag);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_EFI32_IH:
|
||||
{
|
||||
multiboot_tag_efi32_ih *efi32_ih = (multiboot_tag_efi32_ih *)Tag;
|
||||
fixme("efi32_ih->[pointer: %p]", efi32_ih->pointer);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_EFI64_IH:
|
||||
{
|
||||
multiboot_tag_efi64_ih *efi64_ih = (multiboot_tag_efi64_ih *)Tag;
|
||||
fixme("efi64_ih->[pointer: %p]", efi64_ih->pointer);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
|
||||
{
|
||||
multiboot_tag_load_base_addr *load_base_addr = (multiboot_tag_load_base_addr *)Tag;
|
||||
mb2binfo.Kernel.PhysicalBase = (void *)load_base_addr->load_base_addr;
|
||||
mb2binfo.Kernel.VirtualBase = (void *)(load_base_addr->load_base_addr + 0xC0000000);
|
||||
debug("Kernel base: %p (physical) %p (virtual)", mb2binfo.Kernel.PhysicalBase, mb2binfo.Kernel.VirtualBase);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
error("Unknown multiboot2 tag type: %d", Tag->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXTERNC void Multiboot2Entry(unsigned long Info, unsigned int Magic)
|
||||
{
|
||||
if (Info == NULL || Magic == NULL)
|
||||
{
|
||||
if (Magic == NULL)
|
||||
error("Multiboot magic is NULL");
|
||||
if (Info == NULL)
|
||||
error("Multiboot info is NULL");
|
||||
CPU::Stop();
|
||||
}
|
||||
else if (Magic != MULTIBOOT2_BOOTLOADER_MAGIC)
|
||||
{
|
||||
error("Multiboot magic is invalid (%#x != %#x)", Magic, MULTIBOOT2_BOOTLOADER_MAGIC);
|
||||
CPU::Stop();
|
||||
}
|
||||
|
||||
uint64_t div = 1193180 / 1000;
|
||||
outb(0x43, 0xB6);
|
||||
outb(0x42, (uint8_t)div);
|
||||
outb(0x42, (uint8_t)(div >> 8));
|
||||
uint8_t tmp = inb(0x61);
|
||||
if (tmp != (tmp | 3))
|
||||
outb(0x61, tmp | 3);
|
||||
|
||||
ProcessMB2(Info);
|
||||
|
||||
tmp = inb(0x61) & 0xFC;
|
||||
outb(0x61, tmp);
|
||||
|
||||
CPU::Stop();
|
||||
Entry(&mb2binfo);
|
||||
}
|
123
Architecture/i386/Interrupts/8259PIC.cpp
Normal file
123
Architecture/i386/Interrupts/8259PIC.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
#include "pic.hpp"
|
||||
|
||||
#include <io.h>
|
||||
|
||||
namespace PIC
|
||||
{
|
||||
PIC::PIC(uint8_t MasterCommandPort, uint8_t MasterDataPort, uint8_t SlaveCommandPort, uint8_t SlaveDataPort, uint8_t MasterOffset, uint8_t SlaveOffset)
|
||||
{
|
||||
this->MasterCommandPort = MasterCommandPort;
|
||||
this->MasterDataPort = MasterDataPort;
|
||||
this->SlaveCommandPort = SlaveCommandPort;
|
||||
this->SlaveDataPort = SlaveDataPort;
|
||||
this->MasterOffset = MasterOffset;
|
||||
this->SlaveOffset = SlaveOffset;
|
||||
|
||||
MasterMask = 0xFF;
|
||||
SlaveMask = 0xFF;
|
||||
|
||||
// ICW1
|
||||
outb(MasterCommandPort, 0x11);
|
||||
outb(SlaveCommandPort, 0x11);
|
||||
|
||||
// ICW2
|
||||
outb(MasterDataPort, MasterOffset);
|
||||
outb(SlaveDataPort, SlaveOffset);
|
||||
|
||||
// ICW3
|
||||
outb(MasterDataPort, 0x04);
|
||||
outb(SlaveDataPort, 0x02);
|
||||
|
||||
// ICW4
|
||||
outb(MasterDataPort, 0x01);
|
||||
outb(SlaveDataPort, 0x01);
|
||||
|
||||
// OCW1
|
||||
outb(MasterDataPort, MasterMask);
|
||||
outb(SlaveDataPort, SlaveMask);
|
||||
}
|
||||
|
||||
PIC::~PIC()
|
||||
{
|
||||
outb(MasterDataPort, 0xFF);
|
||||
outb(SlaveDataPort, 0xFF);
|
||||
}
|
||||
|
||||
void PIC::Mask(uint8_t IRQ)
|
||||
{
|
||||
uint16_t Port;
|
||||
uint8_t Value;
|
||||
|
||||
if (IRQ < 8)
|
||||
{
|
||||
Port = MasterDataPort;
|
||||
Value = MasterMask & ~(1 << IRQ);
|
||||
MasterMask = Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Port = SlaveDataPort;
|
||||
Value = SlaveMask & ~(1 << (IRQ - 8));
|
||||
SlaveMask = Value;
|
||||
}
|
||||
|
||||
outb(Port, Value);
|
||||
}
|
||||
|
||||
void PIC::Unmask(uint8_t IRQ)
|
||||
{
|
||||
uint16_t Port;
|
||||
uint8_t Value;
|
||||
|
||||
if (IRQ < 8)
|
||||
{
|
||||
Port = MasterDataPort;
|
||||
Value = MasterMask | (1 << IRQ);
|
||||
MasterMask = Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Port = SlaveDataPort;
|
||||
Value = SlaveMask | (1 << (IRQ - 8));
|
||||
SlaveMask = Value;
|
||||
}
|
||||
|
||||
outb(Port, Value);
|
||||
}
|
||||
|
||||
void PIC::SendEOI(uint8_t IRQ)
|
||||
{
|
||||
if (IRQ >= 8)
|
||||
outb(SlaveCommandPort, 0x20);
|
||||
|
||||
outb(MasterCommandPort, 0x20);
|
||||
}
|
||||
|
||||
PIT::PIT(uint16_t Port, uint16_t Frequency)
|
||||
{
|
||||
this->Port = Port;
|
||||
this->Frequency = Frequency;
|
||||
}
|
||||
|
||||
PIT::~PIT()
|
||||
{
|
||||
}
|
||||
|
||||
void PIT::PrepareSleep(uint32_t Milliseconds)
|
||||
{
|
||||
uint16_t Divisor = 1193182 / Frequency;
|
||||
uint8_t Low = (uint8_t)(Divisor & 0xFF);
|
||||
uint8_t High = (uint8_t)((Divisor >> 8) & 0xFF);
|
||||
|
||||
outb(Port + 3, 0x36);
|
||||
outb(Port + 0, Low);
|
||||
outb(Port + 1, High);
|
||||
}
|
||||
|
||||
void PIT::PerformSleep()
|
||||
{
|
||||
uint8_t Value = inb(Port + 0);
|
||||
while (Value != 0)
|
||||
Value = inb(Port + 0);
|
||||
}
|
||||
}
|
42
Architecture/i386/Interrupts/pic.hpp
Normal file
42
Architecture/i386/Interrupts/pic.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef __FENNIX_KERNEL_8259PIC_H__
|
||||
#define __FENNIX_KERNEL_8259PIC_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
namespace PIC
|
||||
{
|
||||
class PIC
|
||||
{
|
||||
private:
|
||||
uint8_t MasterCommandPort;
|
||||
uint8_t MasterDataPort;
|
||||
uint8_t SlaveCommandPort;
|
||||
uint8_t SlaveDataPort;
|
||||
uint8_t MasterOffset;
|
||||
uint8_t SlaveOffset;
|
||||
uint8_t MasterMask;
|
||||
uint8_t SlaveMask;
|
||||
|
||||
public:
|
||||
PIC(uint8_t MasterCommandPort, uint8_t MasterDataPort, uint8_t SlaveCommandPort, uint8_t SlaveDataPort, uint8_t MasterOffset, uint8_t SlaveOffset);
|
||||
~PIC();
|
||||
void Mask(uint8_t IRQ);
|
||||
void Unmask(uint8_t IRQ);
|
||||
void SendEOI(uint8_t IRQ);
|
||||
};
|
||||
|
||||
class PIT
|
||||
{
|
||||
private:
|
||||
uint16_t Port;
|
||||
uint16_t Frequency;
|
||||
|
||||
public:
|
||||
PIT(uint16_t Port, uint16_t Frequency);
|
||||
~PIT();
|
||||
void PrepareSleep(uint32_t Milliseconds);
|
||||
void PerformSleep();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_8259PIC_H__
|
13
Architecture/i386/SystemCalls.cpp
Normal file
13
Architecture/i386/SystemCalls.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include <syscalls.hpp>
|
||||
|
||||
#include <cpu.hpp>
|
||||
|
||||
#include "cpu/gdt.hpp"
|
||||
|
||||
using namespace CPU::x32;
|
||||
|
||||
extern "C" uint32_t SystemCallsHandler(SyscallsFrame *regs);
|
||||
|
||||
void InitializeSystemCalls()
|
||||
{
|
||||
}
|
99
Architecture/i386/cpu/GlobalDescriptorTable.cpp
Normal file
99
Architecture/i386/cpu/GlobalDescriptorTable.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include "gdt.hpp"
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <smp.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
namespace GlobalDescriptorTable
|
||||
{
|
||||
static GlobalDescriptorTableEntries GDTEntriesTemplate = {
|
||||
// null
|
||||
{.Length = 0x0,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {.Raw = 0x0},
|
||||
.Flags = {.Raw = 0x0},
|
||||
.BaseHigh = 0x0},
|
||||
|
||||
// kernel code
|
||||
{.Length = 0x0,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {.A = 0,
|
||||
.RW = 1,
|
||||
.DC = 0,
|
||||
.E = 1,
|
||||
.S = 1,
|
||||
.DPL = 0,
|
||||
.P = 1},
|
||||
.Flags = {.Unknown = 0x0, .L = 1},
|
||||
.BaseHigh = 0x0},
|
||||
|
||||
// kernel data
|
||||
{.Length = 0x0,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {.A = 0,
|
||||
.RW = 1,
|
||||
.DC = 0,
|
||||
.E = 0,
|
||||
.S = 1,
|
||||
.DPL = 0,
|
||||
.P = 1},
|
||||
.Flags = {.Raw = 0x0},
|
||||
.BaseHigh = 0x0},
|
||||
|
||||
// user data
|
||||
{.Length = 0x0,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {.A = 0,
|
||||
.RW = 1,
|
||||
.DC = 0,
|
||||
.E = 0,
|
||||
.S = 1,
|
||||
.DPL = 3,
|
||||
.P = 1},
|
||||
.Flags = {.Raw = 0x0},
|
||||
.BaseHigh = 0x0},
|
||||
|
||||
// user code
|
||||
{.Length = 0x0,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {.A = 0,
|
||||
.RW = 1,
|
||||
.DC = 0,
|
||||
.E = 1,
|
||||
.S = 1,
|
||||
.DPL = 3,
|
||||
.P = 1},
|
||||
.Flags = {.Unknown = 0x0, .L = 1},
|
||||
.BaseHigh = 0x0},
|
||||
|
||||
// tss
|
||||
{}};
|
||||
|
||||
GlobalDescriptorTableEntries GDTEntries[MAX_CPU];
|
||||
GlobalDescriptorTableDescriptor gdt[MAX_CPU];
|
||||
|
||||
TaskStateSegment tss[MAX_CPU] = {
|
||||
0,
|
||||
{0, 0, 0},
|
||||
0,
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
void *CPUStackPointer[MAX_CPU];
|
||||
|
||||
SafeFunction void Init(int Core)
|
||||
{
|
||||
}
|
||||
|
||||
SafeFunction void SetKernelStack(void *Stack)
|
||||
{
|
||||
}
|
||||
}
|
37
Architecture/i386/cpu/SymmetricMultiprocessing.cpp
Normal file
37
Architecture/i386/cpu/SymmetricMultiprocessing.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include <smp.hpp>
|
||||
|
||||
#include <ints.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <assert.h>
|
||||
#include <cpu.hpp>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
|
||||
volatile bool CPUEnabled = false;
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
static __attribute__((aligned(PAGE_SIZE))) CPUData CPUs[MAX_CPU] = {0};
|
||||
|
||||
CPUData *GetCPU(uint64_t id) { return &CPUs[id]; }
|
||||
|
||||
CPUData *GetCurrentCPU()
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
if (!(&CPUs[ret])->IsActive)
|
||||
{
|
||||
error("CPU %d is not active!", ret);
|
||||
return &CPUs[0];
|
||||
}
|
||||
assert((&CPUs[ret])->Checksum == CPU_DATA_CHECKSUM);
|
||||
return &CPUs[ret];
|
||||
}
|
||||
|
||||
namespace SMP
|
||||
{
|
||||
int CPUCores = 0;
|
||||
|
||||
void Initialize(void *madt)
|
||||
{
|
||||
fixme("SMP::Initialize() is not implemented!");
|
||||
}
|
||||
}
|
337
Architecture/i386/cpu/apic.hpp
Normal file
337
Architecture/i386/cpu/apic.hpp
Normal file
@ -0,0 +1,337 @@
|
||||
#ifndef __FENNIX_KERNEL_APIC_H__
|
||||
#define __FENNIX_KERNEL_APIC_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <ints.hpp>
|
||||
#include <cpu.hpp>
|
||||
|
||||
namespace APIC
|
||||
{
|
||||
enum APICRegisters
|
||||
{
|
||||
// source from: https://github.com/pdoane/osdev/blob/master/intr/local_apic.c
|
||||
APIC_ID = 0x20, // Local APIC ID
|
||||
APIC_VER = 0x30, // Local APIC Version
|
||||
APIC_TPR = 0x80, // Task Priority
|
||||
APIC_APR = 0x90, // Arbitration Priority
|
||||
APIC_PPR = 0xA0, // Processor Priority
|
||||
APIC_EOI = 0xB0, // EOI
|
||||
APIC_RRD = 0xC0, // Remote Read
|
||||
APIC_LDR = 0xD0, // Logical Destination
|
||||
APIC_DFR = 0xE0, // Destination Format
|
||||
APIC_SVR = 0xF0, // Spurious Interrupt Vector
|
||||
APIC_ISR = 0x100, // In-Service (8 registers)
|
||||
APIC_TMR = 0x180, // Trigger Mode (8 registers)
|
||||
APIC_IRR = 0x200, // Interrupt Request (8 registers)
|
||||
APIC_ESR = 0x280, // Error Status
|
||||
APIC_ICRLO = 0x300, // Interrupt Command
|
||||
APIC_ICRHI = 0x310, // Interrupt Command [63:32]
|
||||
APIC_TIMER = 0x320, // LVT Timer
|
||||
APIC_THERMAL = 0x330, // LVT Thermal Sensor
|
||||
APIC_PERF = 0x340, // LVT Performance Counter
|
||||
APIC_LINT0 = 0x350, // LVT LINT0
|
||||
APIC_LINT1 = 0x360, // LVT LINT1
|
||||
APIC_ERROR = 0x370, // LVT Error
|
||||
APIC_TICR = 0x380, // Initial Count (for Timer)
|
||||
APIC_TCCR = 0x390, // Current Count (for Timer)
|
||||
APIC_TDCR = 0x3E0, // Divide Configuration (for Timer)
|
||||
};
|
||||
|
||||
enum IOAPICRegisters
|
||||
{
|
||||
GetIOAPICVersion = 0x1
|
||||
};
|
||||
|
||||
enum IOAPICFlags
|
||||
{
|
||||
ActiveHighLow = 2,
|
||||
EdgeLevel = 8
|
||||
};
|
||||
|
||||
enum APICDeliveryMode
|
||||
{
|
||||
Fixed = 0b000,
|
||||
LowestPriority = 0b001, /* Reserved */
|
||||
SMI = 0b010,
|
||||
APIC_DELIVERY_MODE_RESERVED0 = 0b011, /* Reserved */
|
||||
NMI = 0b100,
|
||||
INIT = 0b101,
|
||||
Startup = 0b110,
|
||||
ExtINT = 0b111 /* Reserved */
|
||||
};
|
||||
|
||||
enum APICDestinationMode
|
||||
{
|
||||
Physical = 0b0,
|
||||
Logical = 0b1
|
||||
};
|
||||
|
||||
enum APICDeliveryStatus
|
||||
{
|
||||
Idle = 0b0,
|
||||
SendPending = 0b1
|
||||
};
|
||||
|
||||
enum APICLevel
|
||||
{
|
||||
DeAssert = 0b0,
|
||||
Assert = 0b1
|
||||
};
|
||||
|
||||
enum APICTriggerMode
|
||||
{
|
||||
Edge = 0b0,
|
||||
Level = 0b1
|
||||
};
|
||||
|
||||
enum APICDestinationShorthand
|
||||
{
|
||||
NoShorthand = 0b00,
|
||||
Self = 0b01,
|
||||
AllIncludingSelf = 0b10,
|
||||
AllExcludingSelf = 0b11
|
||||
};
|
||||
|
||||
enum LVTTimerDivide
|
||||
{
|
||||
DivideBy2 = 0b000,
|
||||
DivideBy4 = 0b001,
|
||||
DivideBy8 = 0b010,
|
||||
DivideBy16 = 0b011,
|
||||
DivideBy32 = 0b100,
|
||||
DivideBy64 = 0b101,
|
||||
DivideBy128 = 0b110,
|
||||
DivideBy1 = 0b111
|
||||
};
|
||||
|
||||
enum LVTTimerMask
|
||||
{
|
||||
Unmasked = 0b0,
|
||||
Masked = 0b1
|
||||
};
|
||||
|
||||
enum LVTTimerMode
|
||||
{
|
||||
OneShot = 0b00,
|
||||
Periodic = 0b01,
|
||||
TSCDeadline = 0b10
|
||||
};
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Interrupt Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved0 : 4;
|
||||
/**
|
||||
* @brief Delivery Status
|
||||
*
|
||||
* 0: Idle
|
||||
* 1: Send Pending
|
||||
*/
|
||||
uint64_t DeliveryStatus : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved1 : 3;
|
||||
/**
|
||||
* @brief Mask
|
||||
*
|
||||
* 0: Not masked
|
||||
* 1: Masked
|
||||
*/
|
||||
uint64_t Mask : 1;
|
||||
/** @brief Timer Mode
|
||||
*
|
||||
* 0: One-shot
|
||||
* 1: Periodic
|
||||
* 2: TSC-Deadline
|
||||
*/
|
||||
uint64_t TimerMode : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved2 : 14;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __attribute__((packed)) LVTTimer;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Spurious Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Enable or disable APIC software */
|
||||
uint64_t Software : 1;
|
||||
/** @brief Focus Processor Checking */
|
||||
uint64_t FocusProcessorChecking : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved : 2;
|
||||
/** @brief Disable EOI Broadcast */
|
||||
uint64_t DisableEOIBroadcast : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved1 : 19;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __attribute__((packed)) Spurious;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Interrupt Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Delivery Mode */
|
||||
uint64_t DeliveryMode : 3;
|
||||
/** @brief Destination Mode
|
||||
*
|
||||
* 0: Physical
|
||||
* 1: Logical
|
||||
*/
|
||||
uint64_t DestinationMode : 1;
|
||||
/** @brief Delivery Status
|
||||
*
|
||||
* @note Reserved when in x2APIC mode
|
||||
*/
|
||||
uint64_t DeliveryStatus : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved0 : 1;
|
||||
/** @brief Level
|
||||
*
|
||||
* 0: Deassert
|
||||
* 1: Assert
|
||||
*/
|
||||
uint64_t Level : 1;
|
||||
/** @brief Trigger Mode
|
||||
*
|
||||
* 0: Edge
|
||||
* 1: Level
|
||||
*/
|
||||
uint64_t TriggerMode : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved1 : 2;
|
||||
/** @brief Destination Shorthand
|
||||
*
|
||||
* 0: No shorthand
|
||||
* 1: Self
|
||||
* 2: All including self
|
||||
* 3: All excluding self
|
||||
*/
|
||||
uint64_t DestinationShorthand : 2;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved2 : 12;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __attribute__((packed)) InterruptCommandRegisterLow;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved0 : 24;
|
||||
/** @brief Destination */
|
||||
uint64_t Destination : 8;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __attribute__((packed)) InterruptCommandRegisterHigh;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Interrupt Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Delivery Mode */
|
||||
uint64_t DeliveryMode : 3;
|
||||
/** @brief Destination Mode
|
||||
*
|
||||
* 0: Physical
|
||||
* 1: Logical
|
||||
*/
|
||||
uint64_t DestinationMode : 1;
|
||||
/** @brief Delivery Status */
|
||||
uint64_t DeliveryStatus : 1;
|
||||
/** @brief Interrupt Input Pin Polarity
|
||||
*
|
||||
* 0: Active High
|
||||
* 1: Active Low
|
||||
*/
|
||||
uint64_t Polarity : 1;
|
||||
/** @brief Remote IRR */
|
||||
uint64_t RemoteIRR : 1;
|
||||
/** @brief Trigger Mode
|
||||
*
|
||||
* 0: Edge
|
||||
* 1: Level
|
||||
*/
|
||||
uint64_t TriggerMode : 1;
|
||||
/** @brief Mask */
|
||||
uint64_t Mask : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved0 : 15;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved1 : 24;
|
||||
/** @brief Destination */
|
||||
uint64_t DestinationID : 8;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint64_t Low;
|
||||
uint64_t High;
|
||||
} split;
|
||||
uint64_t raw;
|
||||
} __attribute__((packed)) IOAPICRedirectEntry;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint64_t Version : 8;
|
||||
uint64_t Reserved : 8;
|
||||
uint64_t MaximumRedirectionEntry : 8;
|
||||
uint64_t Reserved2 : 8;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __attribute__((packed)) IOAPICVersion;
|
||||
|
||||
class APIC
|
||||
{
|
||||
private:
|
||||
bool x2APICSupported = false;
|
||||
uint64_t APICBaseAddress = 0;
|
||||
|
||||
public:
|
||||
uint32_t Read(uint32_t Register);
|
||||
void Write(uint32_t Register, uint32_t Value);
|
||||
void IOWrite(uint64_t Base, uint32_t Register, uint32_t Value);
|
||||
uint32_t IORead(uint64_t Base, uint32_t Register);
|
||||
void EOI();
|
||||
void RedirectIRQs(int CPU = 0);
|
||||
void WaitForIPI();
|
||||
void IPI(uint8_t CPU, InterruptCommandRegisterLow icr);
|
||||
void SendInitIPI(uint8_t CPU);
|
||||
void SendStartupIPI(uint8_t CPU, uint64_t StartupAddress);
|
||||
uint32_t IOGetMaxRedirect(uint32_t APICID);
|
||||
void RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status);
|
||||
void RedirectIRQ(int CPU, uint16_t IRQ, int Status);
|
||||
APIC(int Core);
|
||||
~APIC();
|
||||
};
|
||||
|
||||
class Timer : public Interrupts::Handler
|
||||
{
|
||||
private:
|
||||
APIC *lapic;
|
||||
uint64_t Ticks = 0;
|
||||
void OnInterruptReceived(CPU::x32::TrapFrame *Frame);
|
||||
|
||||
public:
|
||||
uint64_t GetTicks() { return Ticks; }
|
||||
void OneShot(uint32_t Vector, uint64_t Miliseconds);
|
||||
Timer(APIC *apic);
|
||||
~Timer();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_APIC_H__
|
145
Architecture/i386/cpu/gdt.hpp
Normal file
145
Architecture/i386/cpu/gdt.hpp
Normal file
@ -0,0 +1,145 @@
|
||||
#ifndef __FENNIX_KERNEL_GDT_H__
|
||||
#define __FENNIX_KERNEL_GDT_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
namespace GlobalDescriptorTable
|
||||
{
|
||||
/** @brief The GDT Access Table
|
||||
* @details For more information, see https://wiki.osdev.org/Global_Descriptor_Table
|
||||
*/
|
||||
union GlobalDescriptorTableAccess
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Access bit.
|
||||
* @note The CPU sets this bit to 1 when the segment is accessed.
|
||||
*/
|
||||
uint8_t A : 1;
|
||||
|
||||
/** @brief Readable bit for code segments, writable bit for data segments.
|
||||
* @details For code segments, this bit must be 1 for the segment to be readable.
|
||||
* @details For data segments, this bit must be 1 for the segment to be writable.
|
||||
*/
|
||||
uint8_t RW : 1;
|
||||
|
||||
/** @brief Direction bit for data segments, conforming bit for code segments.
|
||||
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
|
||||
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
|
||||
*/
|
||||
uint8_t DC : 1;
|
||||
|
||||
/** @brief Executable bit.
|
||||
* @details This bit must be 1 for code-segment descriptors.
|
||||
* @details This bit must be 0 for data-segment and system descriptors.
|
||||
*/
|
||||
uint8_t E : 1;
|
||||
|
||||
/** @brief Descriptor type.
|
||||
* @details This bit must be 0 for system descriptors.
|
||||
* @details This bit must be 1 for code or data segment descriptor.
|
||||
*/
|
||||
uint8_t S : 1;
|
||||
|
||||
/** @brief Descriptor privilege level.
|
||||
* @details This field determines the privilege level of the segment.
|
||||
* @details 0 = kernel mode, 3 = user mode.
|
||||
*/
|
||||
uint8_t DPL : 2;
|
||||
|
||||
/** @brief Present bit.
|
||||
* @details This bit must be 1 for all valid descriptors.
|
||||
*/
|
||||
uint8_t P : 1;
|
||||
} __attribute__((packed));
|
||||
uint8_t Raw;
|
||||
};
|
||||
|
||||
union GlobalDescriptorTableFlags
|
||||
{
|
||||
// TODO: Add more flags.
|
||||
struct
|
||||
{
|
||||
/** @brief Unknown. */
|
||||
uint8_t Unknown : 5;
|
||||
|
||||
/** @brief Long mode.
|
||||
* @details If the long mode bit is clear, the segment is in 32-bit protected mode.
|
||||
* @details If the long mode bit is set, the segment is in 64-bit long mode.
|
||||
*/
|
||||
uint8_t L : 1;
|
||||
} __attribute__((packed));
|
||||
uint8_t Raw;
|
||||
};
|
||||
|
||||
typedef struct _TaskStateSegmentEntry
|
||||
{
|
||||
/* LOW */
|
||||
uint16_t Length;
|
||||
uint16_t BaseLow;
|
||||
uint8_t BaseMiddle;
|
||||
GlobalDescriptorTableAccess Flags;
|
||||
uint8_t Granularity;
|
||||
uint8_t BaseHigh;
|
||||
/* HIGH */
|
||||
uint32_t BaseUpper;
|
||||
uint32_t Reserved;
|
||||
} __attribute__((packed)) TaskStateSegmentEntry;
|
||||
|
||||
typedef struct _TaskStateSegment
|
||||
{
|
||||
uint32_t Reserved0 __attribute__((aligned(16)));
|
||||
uint64_t StackPointer[3];
|
||||
uint64_t Reserved1;
|
||||
uint64_t InterruptStackTable[7];
|
||||
uint16_t Reserved2;
|
||||
uint16_t IOMapBaseAddressOffset;
|
||||
} __attribute__((packed)) TaskStateSegment;
|
||||
|
||||
typedef struct _GlobalDescriptorTableEntry
|
||||
{
|
||||
/** @brief Length */
|
||||
uint16_t Length;
|
||||
/** @brief Low Base */
|
||||
uint16_t BaseLow;
|
||||
/** @brief Middle Base */
|
||||
uint8_t BaseMiddle;
|
||||
/** @brief Access */
|
||||
GlobalDescriptorTableAccess Access;
|
||||
/** @brief Flags */
|
||||
GlobalDescriptorTableFlags Flags;
|
||||
/** @brief High Base */
|
||||
uint8_t BaseHigh;
|
||||
} __attribute__((packed)) GlobalDescriptorTableEntry;
|
||||
|
||||
typedef struct _GlobalDescriptorTableEntries
|
||||
{
|
||||
GlobalDescriptorTableEntry Null;
|
||||
GlobalDescriptorTableEntry Code;
|
||||
GlobalDescriptorTableEntry Data;
|
||||
GlobalDescriptorTableEntry UserData;
|
||||
GlobalDescriptorTableEntry UserCode;
|
||||
TaskStateSegmentEntry TaskStateSegment;
|
||||
} __attribute__((packed)) GlobalDescriptorTableEntries;
|
||||
|
||||
typedef struct _GlobalDescriptorTableDescriptor
|
||||
{
|
||||
/** @brief GDT entries length */
|
||||
uint16_t Length;
|
||||
/** @brief GDT entries address */
|
||||
GlobalDescriptorTableEntries *Entries;
|
||||
} __attribute__((packed)) GlobalDescriptorTableDescriptor;
|
||||
|
||||
extern void *CPUStackPointer[];
|
||||
extern TaskStateSegment tss[];
|
||||
void Init(int Core);
|
||||
void SetKernelStack(void *Stack);
|
||||
}
|
||||
|
||||
#define GDT_KERNEL_CODE offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Code)
|
||||
#define GDT_KERNEL_DATA offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Data)
|
||||
#define GDT_USER_CODE (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, UserCode) | 3)
|
||||
#define GDT_USER_DATA (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, UserData) | 3)
|
||||
#define GDT_TSS (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, TaskStateSegment) | 3)
|
||||
|
||||
#endif // !__FENNIX_KERNEL_GDT_H__
|
11
Architecture/i386/cpu/idt.hpp
Normal file
11
Architecture/i386/cpu/idt.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef __FENNIX_KERNEL_IDT_H__
|
||||
#define __FENNIX_KERNEL_IDT_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
namespace InterruptDescriptorTable
|
||||
{
|
||||
void Init(int Core);
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_IDT_H__
|
59
Architecture/i386/linker.ld
Normal file
59
Architecture/i386/linker.ld
Normal file
@ -0,0 +1,59 @@
|
||||
OUTPUT_FORMAT(elf32-i386)
|
||||
OUTPUT_ARCH(i386)
|
||||
|
||||
ENTRY(MB2_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xC0100000;
|
||||
_kernel_start = .;
|
||||
|
||||
.text ALIGN(4096) : AT(ADDR(.text) - 0xC0000000)
|
||||
{
|
||||
*(.multiboot2)
|
||||
*(.text .text.*)
|
||||
}
|
||||
_kernel_text_end = .;
|
||||
|
||||
.data ALIGN (4096) : AT(ADDR(.data) - 0xC0000000)
|
||||
{
|
||||
*(.data .data.*)
|
||||
}
|
||||
_kernel_data_end = .;
|
||||
|
||||
.rodata ALIGN (4096) : AT(ADDR(.rodata) - 0xC0000000)
|
||||
{
|
||||
*(.rodata .rodata.*)
|
||||
}
|
||||
_kernel_rodata_end = .;
|
||||
|
||||
.init_array :
|
||||
{
|
||||
PROVIDE_HIDDEN(__init_array_start = .);
|
||||
KEEP(*(.init_array .ctors))
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
}
|
||||
|
||||
.fini_array :
|
||||
{
|
||||
PROVIDE_HIDDEN(__fini_array_start = .);
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||
KEEP(*(.fini_array .dtors))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
}
|
||||
. += CONSTANT(MAXPAGESIZE);
|
||||
|
||||
.bss ALIGN (4096) : AT(ADDR(.bss) - 0xC0000000)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss .bss.*)
|
||||
}
|
||||
_kernel_end = .;
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.comment*)
|
||||
*(.note*)
|
||||
}
|
||||
}
|
15
Architecture/i386/runtime/crt0.c
Normal file
15
Architecture/i386/runtime/crt0.c
Normal file
@ -0,0 +1,15 @@
|
||||
// #include <types.h>
|
||||
|
||||
// #include <debug.h>
|
||||
|
||||
// int Entry(void *Info);
|
||||
|
||||
// void _start(void *Raw)
|
||||
// {
|
||||
// error("Todo");
|
||||
// while (1)
|
||||
// asmv("hlt");
|
||||
// Entry(NULL);
|
||||
// return;
|
||||
// }
|
||||
// C stuff
|
15
Architecture/i386/runtime/crt1.c
Normal file
15
Architecture/i386/runtime/crt1.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include <types.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
int Entry(void *Info);
|
||||
|
||||
void _start(void *Raw)
|
||||
{
|
||||
UNUSED(Raw);
|
||||
error("ERROR! INVALID BOOT PROTOCOL!");
|
||||
while (1)
|
||||
asmv("hlt");
|
||||
Entry(NULL);
|
||||
return;
|
||||
}
|
1
Architecture/i386/runtime/crtbegin.c
Normal file
1
Architecture/i386/runtime/crtbegin.c
Normal file
@ -0,0 +1 @@
|
||||
// C++ constructor/destructor stuff
|
1
Architecture/i386/runtime/crtend.c
Normal file
1
Architecture/i386/runtime/crtend.c
Normal file
@ -0,0 +1 @@
|
||||
// C++ constructor/destructor stuff
|
13
Architecture/i386/runtime/crti.S
Normal file
13
Architecture/i386/runtime/crti.S
Normal file
@ -0,0 +1,13 @@
|
||||
.section .init
|
||||
.global _init
|
||||
.type _init, @function
|
||||
_init:
|
||||
push %ebp
|
||||
mov %esp, %ebp
|
||||
|
||||
.section .fini
|
||||
.global _fini
|
||||
.type _fini, @function
|
||||
_fini:
|
||||
push %ebp
|
||||
mov %esp, %ebp
|
7
Architecture/i386/runtime/crtn.S
Normal file
7
Architecture/i386/runtime/crtn.S
Normal file
@ -0,0 +1,7 @@
|
||||
.section .init
|
||||
pop %ebp
|
||||
ret
|
||||
|
||||
.section .fini
|
||||
pop %ebp
|
||||
ret
|
Reference in New Issue
Block a user