Skip to content

Commit

Permalink
preliminary x86_64 linux support
Browse files Browse the repository at this point in the history
  • Loading branch information
aarkegz committed Nov 23, 2023
1 parent 2efe5dc commit 26cd265
Show file tree
Hide file tree
Showing 25 changed files with 1,553 additions and 48 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
60 changes: 60 additions & 0 deletions apps/hv/guest/vlbl/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
OUT ?= out

entry-src := entry.S
entry-obj := $(OUT)/entry.o
loader-src := loader.c
loader-obj := $(OUT)/loader.o
virt-int-src := virt_int.S
virt-int-obj := $(OUT)/virt_int.o
virt-int-c-src := virt_int.c
virt-int-c-obj := $(OUT)/virt_int_c.o

ldscript := vlbl.lds
target := $(OUT)/vlbl
target-objs := $(entry-obj) $(loader-obj) $(virt-int-obj) $(virt-int-c-obj)
target-elf := $(target).elf
target-bin := $(target).bin
target-disasm-16 := $(target).16.asm
target-disasm-32 := $(target).32.asm

CC ?= gcc
AS ?= as
LD ?= ld
OBJCOPY ?= objcopy
OBJDUMP ?= objdump

all: $(OUT) $(target).bin disasm

disasm: disasm16 disasm32

disasm16:
$(OBJDUMP) -D -m i8086 -M intel $(target-elf) > $(target-disasm-16)

disasm32:
$(OBJDUMP) -D -m i386 -M intel $(target-elf) > $(target-disasm-32)

$(OUT):
mkdir -p $(OUT)

$(entry-obj): $(entry-src)
$(AS) --32 -msyntax=intel -mnaked-reg $< -o $@

$(loader-obj): $(loader-src)
$(CC) -m32 -fno-pie -fno-builtin -Os -c $< -o $@

$(virt-int-obj): $(virt-int-src)
$(AS) --32 -msyntax=intel -mnaked-reg $< -o $@

$(virt-int-c-obj): $(virt-int-c-src)
$(CC) -m16 -march=i386 -fno-pie -fno-builtin -Os -c $< -o $@

$(target-elf): $(target-objs) $(ldscript)
$(LD) -T$(ldscript) $(target-objs) -o $@

$(target-bin): $(target-elf)
$(OBJCOPY) $< --strip-all -O binary $@

clean:
rm -rf $(OUT)

.PHONY: all disasm clean
71 changes: 71 additions & 0 deletions apps/hv/guest/vlbl/defs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* as we do not have 64-bit codes here, it's safe to assume that */
typedef unsigned char uint8_t, *uint8_p;
typedef unsigned short int uint16_t, *uint16_p;
typedef unsigned long int uint32_t, *uint32_p;
typedef signed char int8_t, *int8_p;
typedef signed short int int16_t, *int16_p;
typedef signed long int int32_t, *int32_p;

#ifndef bool
typedef uint8_t bool;
# define true (1)
# define false (0)
#endif

static inline void outb(uint8_t value, uint16_t port) {
asm volatile("outb %b0, %w1" : : "a"(value), "Nd"(port));
}

#define COM1 0x3f8
static inline void putchar(char c) {
outb((uint8_t)c, COM1);
}

static inline void putsi(const char *s) {
while (*s != '\0') {
putchar(*(s++));
}
}

static inline void puts(const char *s) {
putsi(s);
putchar('\n');
}

static inline void putud(uint32_t num) {
static char buf[12];
int8_t cnt = 0;
while (num > 0) {
buf[cnt++] = '0' + num % 10;
num /= 10;
}

while (--cnt >= 0) {
putchar(buf[cnt]);
}
}

static inline void putux(uint32_t num, bool prefix, int8_t padding) {
static char buf[10];
const char *chars = "0123456789abcdef";
int8_t cnt = 0;
while (num > 0) {
buf[cnt++] = chars[num % 16];
num /= 16;
}

if (padding > cnt && padding <= 10) {
while (cnt < padding) {
buf[cnt++] = '0';
}
}

if (prefix) {
putchar('0');
putchar('x');
}

while (--cnt >= 0) {
putchar(buf[cnt]);
}
}
128 changes: 128 additions & 0 deletions apps/hv/guest/vlbl/entry.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# it's 7c00 here
.section .text
.code16
.global entry
entry:
cli
cld

# 初始化段寄存器
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax

# 进入保护模式
lgdt [prot_gdt_desc]
mov eax, cr0
or eax, 0x1
mov cr0, eax

ljmp 0x8, entry32

.code32
.global entry32
entry32:
# 初始化段选择子到数据段
mov ax, 0x10
mov ds, ax
mov es, ax
mov ss, ax
mov fs, ax
mov gs, ax

# 初始化临时栈
mov ebp, 0x7b00
mov esp, 0x7b00

# 加载内核
push 0x00100000 # 32-bit 加载地址
push 0x0001e000 # 栈顶地址
push 0x00010000 # 16-bit 加载地址
push 0x70200000 # 镜像地址
call load_kernel

# 跳转到16-bit保护模式
lgdt [prot_16_gdt_desc]
ljmp 0x8, entry_prot_16


.code16
.global entry_prot_16
entry_prot_16:
# 再次初始化段选择子到数据段
mov ax, 0x10
mov ds, ax
mov es, ax
mov ss, ax
mov fs, ax
mov gs, ax

# 加载中断向量表
lidt [real_idt_dest]

# 关闭保护模式
mov eax, cr0
or eax, 0x1
xor eax, 0x1
mov cr0, eax

# 跳转到实模式
ljmp 0x0, entry_last_jump

.code16
.global entry_last_jump
entry_last_jump:
# 初始化段寄存器和栈,准备启动
mov ax, 0x1000
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov sp, 0xe000

# 清理寄存器
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
xor ebp, ebp
xor esi, esi
xor edi, edi

# 跳转到linux内核入口
ljmp 0x1020, 0

# 以下代码不应该被执行,使用一条无效的in指令返回
in ax, 0x11
jmp $

.global end_of_code
end_of_code:

# 32位GDT
.balign 16
.global prot_gdt
prot_gdt:
.quad 0x0000000000000000 # 0x00: null
.quad 0x00cf9b000000ffff # 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k)
.quad 0x00cf93000000ffff # 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k)

.global prot_gdt_desc
prot_gdt_desc:
.short prot_gdt_desc - prot_gdt - 1 # limit
.long prot_gdt # base

# 16位GDT
.balign 16
.global prot_16_gdt
prot_16_gdt:
.quad 0x0000000000000000 # 0x00: null
.quad 0x000f9b000000ffff # 0x08: code segment (base=0, limit=0xfffff, type=16bit code exec/read, DPL=0, byte)
.quad 0x000f93000000ffff # 0x10: data segment (base=0, limit=0xfffff, type=16bit data read/write, DPL=0, byte)

.global prot_16_gdt_desc
prot_16_gdt_desc:
.short prot_16_gdt_desc - prot_16_gdt - 1 # limit
.long prot_16_gdt # base
92 changes: 92 additions & 0 deletions apps/hv/guest/vlbl/loader.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#include "defs.h"

#pragma pack(push, 1)
typedef struct _kernel_header {
uint8_t _01f0;
uint8_t setup_sects;
uint16_t root_flags;
uint32_t syssize;
uint16_t ramsize;
uint16_t vid_mode;
uint16_t root_dev;
uint16_t boot_flag;
uint16_t jump;
uint32_t header;
uint16_t version;
uint32_t realmode_swtch;
uint16_t start_sys_seg;
uint16_t kernel_version;
uint8_t type_of_loader;
uint8_t loadflags;
uint16_t setup_move_size;
uint32_t code32_start;
uint32_t ramdisk_image;
uint32_t ramdisk_size;
uint32_t bootsect_kludge;
uint16_t heap_end_ptr;
uint8_t ext_loader_ver;
uint8_t ext_loader_type;
uint32_t cmd_line_ptr;
uint32_t initrd_addr_max;
uint32_t kernel_alignment;
uint8_t relocatable_kernel;
uint8_t min_alignment;
uint16_t xloadflags;
uint32_t cmdline_size;
uint32_t hardware_subarch;
uint32_t hardware_subarch_data_l;
uint32_t hardware_subarch_data_h;
uint32_t payload_offset;
uint32_t payload_length;
uint32_t setup_data_l;
uint32_t setup_data_h;
uint32_t pref_address_l;
uint32_t pref_address_h;
uint32_t init_size;
uint32_t handover_offset;
uint32_t kernel_info_offset;
} kernel_header, *kernel_header_ptr;
#pragma pack(pop)

void cpy4(void *dst, const void *src, uint32_t size) {
const uint32_t * ptr_src = src;
uint32_p ptr_dst = dst;
for (int i = 0; i < size; i += 4) {
*ptr_dst = *ptr_src;
ptr_src++;
ptr_dst++;
}
}

const char cmd[256] = "console=uart8250,io,0x3f8,115200n8 debug root=/dev/vda\0";

int load_kernel(void *kernel_image, void *loc_real, void *stack_end, void *loc_prot) {
kernel_header_ptr orig_header = kernel_image + 0x1f0;

uint32_t kernel_lower_size = ((orig_header->setup_sects ? orig_header->setup_sects : 4) + 1) * 512;
uint32_t kernel_upper_size = orig_header->syssize * 16;
void *prot = kernel_image + kernel_lower_size;

cpy4(loc_real, kernel_image, kernel_lower_size);
cpy4(loc_prot, prot, kernel_upper_size);

void *cmd_base = stack_end;
void *setup_data_base = cmd_base + 256;

cpy4(cmd_base, cmd, 256);

kernel_header_ptr header = loc_real + 0x1f0;

header->vid_mode = 0xffff;
header->type_of_loader = 0xff;
header->loadflags = (header->loadflags & 0x1f) | 0x80;
header->code32_start = (uint32_t)(loc_prot);
header->ramdisk_image = 0;
header->ramdisk_size = 0;
header->heap_end_ptr = (uint16_t)(stack_end - loc_real - 0x200);
header->cmd_line_ptr = (uint32_t)cmd_base;
header->setup_data_l = 0;
header->setup_data_h = 0;

return 0;
}
Loading

0 comments on commit 26cd265

Please sign in to comment.