More experiments with loading Linux.

parent 10cc4561
Pipeline #59816606 canceled with stages
in 25 minutes and 28 seconds
Subproject commit 279992a8f9a23ddb2db5bcb9000c30874e4877a0
Subproject commit 4cd83cd88399b033b7ccd7b98a0e3d60a3f1df97
......@@ -5,97 +5,6 @@
#include <string.h>
#include <asmc_api.h>
struct gdt_entry {
unsigned int limit_low : 16;
unsigned int base_low : 24;
// Access byte
unsigned int accessed : 1;
unsigned int read_write : 1; // Readable for code, writable for data
unsigned int conforming : 1; // Conforming for code, expand down for data
unsigned int code : 1; // 1 for code, 0 for data
unsigned int type : 1; // 1 for code/data, 0 for system segments (like TSS)
unsigned int DPL : 2; //priviledge level
unsigned int present : 1;
// Flags
unsigned int limit_high : 4;
unsigned int always_0 : 2;
unsigned int size : 1; // 1 for 32 bits, 0 for 16 bits
unsigned int gran : 1; // 1 for 4k page addressing, 0 for byte addressing
unsigned int base_high : 8;
} __attribute__((packed));
struct gdt_desc {
uint16_t size;
struct gdt_entry *offset;
} __attribute__((packed));
void reload_gdt(struct gdt_entry *gdt, int entry_num) {
struct gdt_desc desc;
desc.size = entry_num * 8 - 1;
desc.offset = gdt;
asm volatile("lgdt %0 \n\t"
"push $0x10 \n\t"
"push $reload_cs \n\t"
// TCC does not know retf
".byte 0xcb \n\t"
"reload_cs: \n\t"
"mov $0x18, %%ax \n\t"
// TCC generates a 0x66 prefix that does not look like right
/*"mov %%ax, %%ds \n\t"
"mov %%ax, %%es \n\t"
"mov %%ax, %%fs \n\t"
"mov %%ax, %%gs \n\t"
"mov %%ax, %%ss \n\t"*/
".byte 0x8e, 0xd8 \n\t"
".byte 0x8e, 0xc0 \n\t"
".byte 0x8e, 0xe0 \n\t"
".byte 0x8e, 0xe8 \n\t"
".byte 0x8e, 0xd0 \n\t"
: : "m" (desc));
printf("Still alive after reloading code and data segments!\n");
}
// Load GDT, code and data segments according to Linux Boot Protocol
void load_linux_gdt() {
assert(sizeof(struct gdt_desc) == 6);
assert(sizeof(struct gdt_entry) == 8);
// Random address, hoping that it does not bother anybody
struct gdt_entry *gdt = (struct gdt_entry*) 0x800;
memset(gdt, 0, sizeof(gdt[0]) * 4);
// 0x10: code segment
gdt[2].limit_low = 0xffff;
gdt[2].base_low = 0x000000;
gdt[2].accessed = 0;
gdt[2].read_write = 1;
gdt[2].conforming = 0;
gdt[2].code = 1;
gdt[2].type = 1;
gdt[2].DPL = 0;
gdt[2].present = 1;
gdt[2].limit_high = 0xf;
gdt[2].size = 1;
gdt[2].gran = 1;
gdt[2].base_high = 0x00;
// 0x18: data segment
gdt[3].limit_low = 0xffff;
gdt[3].base_low = 0x000000;
gdt[3].accessed = 0;
gdt[3].read_write = 1;
gdt[3].conforming = 0;
gdt[3].code = 0;
gdt[3].type = 1;
gdt[3].DPL = 0;
gdt[3].present = 1;
gdt[3].limit_high = 0xf;
gdt[3].size = 1;
gdt[3].gran = 1;
gdt[3].base_high = 0x00;
reload_gdt(gdt, 4);
}
typedef uint8_t __u8;
typedef uint16_t __u16;
typedef uint32_t __u32;
......@@ -429,6 +338,136 @@ struct boot_params {
__u8 _pad9[276]; /* 0xeec */
} __attribute__((packed));
struct gdt_entry {
unsigned int limit_low : 16;
unsigned int base_low : 24;
// Access byte
unsigned int accessed : 1;
unsigned int read_write : 1; // Readable for code, writable for data
unsigned int conforming : 1; // Conforming for code, expand down for data
unsigned int code : 1; // 1 for code, 0 for data
unsigned int type : 1; // 1 for code/data, 0 for system segments (like TSS)
unsigned int DPL : 2; //priviledge level
unsigned int present : 1;
// Flags
unsigned int limit_high : 4;
unsigned int always_0 : 2;
unsigned int size : 1; // 1 for 32 bits, 0 for 16 bits
unsigned int gran : 1; // 1 for 4k page addressing, 0 for byte addressing
unsigned int base_high : 8;
} __attribute__((packed));
struct gdt_desc {
uint16_t size;
struct gdt_entry *offset;
} __attribute__((packed));
void reload_gdt(struct gdt_entry *gdt, int entry_num) {
struct gdt_desc desc;
desc.size = entry_num * 8 - 1;
desc.offset = gdt;
asm volatile("lgdt %0 \n\t"
"push $0x10 \n\t"
"push $reload_cs \n\t"
// TCC does not know retf
".byte 0xcb \n\t"
"reload_cs: \n\t"
"mov $0x18, %%ax \n\t"
// TCC generates a 0x66 prefix that does not look like right
/*"mov %%ax, %%ds \n\t"
"mov %%ax, %%es \n\t"
"mov %%ax, %%fs \n\t"
"mov %%ax, %%gs \n\t"
"mov %%ax, %%ss \n\t"*/
".byte 0x8e, 0xd8 \n\t"
".byte 0x8e, 0xc0 \n\t"
".byte 0x8e, 0xe0 \n\t"
".byte 0x8e, 0xe8 \n\t"
".byte 0x8e, 0xd0 \n\t"
: : "m" (desc));
printf("Still alive after reloading code and data segments!\n");
}
// Load GDT, code and data segments according to Linux Boot Protocol
void load_linux_gdt() {
assert(sizeof(struct gdt_desc) == 6);
assert(sizeof(struct gdt_entry) == 8);
// Random address, hoping that it does not bother anybody
struct gdt_entry *gdt = (struct gdt_entry*) 0x800;
memset(gdt, 0, sizeof(gdt[0]) * 4);
// 0x10: code segment
gdt[2].limit_low = 0xffff;
gdt[2].base_low = 0x000000;
gdt[2].accessed = 0;
gdt[2].read_write = 1;
gdt[2].conforming = 0;
gdt[2].code = 1;
gdt[2].type = 1;
gdt[2].DPL = 0;
gdt[2].present = 1;
gdt[2].limit_high = 0xf;
gdt[2].size = 1;
gdt[2].gran = 1;
gdt[2].base_high = 0x00;
// 0x18: data segment
gdt[3].limit_low = 0xffff;
gdt[3].base_low = 0x000000;
gdt[3].accessed = 0;
gdt[3].read_write = 1;
gdt[3].conforming = 0;
gdt[3].code = 0;
gdt[3].type = 1;
gdt[3].DPL = 0;
gdt[3].present = 1;
gdt[3].limit_high = 0xf;
gdt[3].size = 1;
gdt[3].gran = 1;
gdt[3].base_high = 0x00;
reload_gdt(gdt, 4);
}
// Prepare GDT to re-enter real mode
void prepare_real_mode_gdt() {
assert(sizeof(struct gdt_desc) == 6);
assert(sizeof(struct gdt_entry) == 8);
// Random address, hoping that it does not bother anybody
struct gdt_entry *gdt = (struct gdt_entry*) 0x800;
memset(gdt, 0, sizeof(gdt[0]) * 4);
// 0x10: code segment
gdt[2].limit_low = 0xffff;
gdt[2].base_low = 0x000000;
gdt[2].accessed = 0;
gdt[2].read_write = 1;
gdt[2].conforming = 0;
gdt[2].code = 1;
gdt[2].type = 1;
gdt[2].DPL = 0;
gdt[2].present = 1;
gdt[2].limit_high = 0x0;
gdt[2].size = 0;
gdt[2].gran = 0;
gdt[2].base_high = 0x00;
// 0x18: data segment
gdt[3].limit_low = 0xffff;
gdt[3].base_low = 0x000000;
gdt[3].accessed = 0;
gdt[3].read_write = 1;
gdt[3].conforming = 0;
gdt[3].code = 0;
gdt[3].type = 1;
gdt[3].DPL = 0;
gdt[3].present = 1;
gdt[3].limit_high = 0x0;
gdt[3].size = 0;
gdt[3].gran = 0;
gdt[3].base_high = 0x00;
}
void *read_all_file(FILE *fin, size_t **size) {
size_t buf_size = 16;
char *buf = malloc(buf_size);
......@@ -459,14 +498,15 @@ void prepare_boot_params(struct boot_params *real_mode) {
hdr->loadflags = 0x81;
hdr->ramdisk_image = 0;
hdr->ramdisk_size = 0;
hdr->heap_end_ptr = 0; // FIXME
hdr->cmd_line_ptr = 0; // FIXME
hdr->heap_end_ptr = 0xde00;
hdr->cmd_line_ptr = 0x1e000;
}
#define SECT_SIZE 512
void load_linux() {
download_file("http://10.0.2.2:8080/bzImage", "/ram/cont/bzImage");
download_file("http://10.0.2.2:8080/realmode.bin", "/ram/cont/realmode.bin");
printf("Loading Linux kernel\n");
FILE *fin = fopen("/ram/cont/bzImage", "rb");
struct boot_params *real_mode = malloc(SECT_SIZE);
......@@ -487,7 +527,24 @@ void load_linux() {
printf("Protected mode code/data is 0x%x bytes long\n", prot_mode_size);
fclose(fin);
prepare_boot_params(real_mode);
load_linux_gdt();
//load_linux_gdt();
fin = fopen("/ram/cont/realmode.bin", "rb");
size_t trampoline_size;
void *trampoline = read_all_file(fin, &trampoline_size);
printf("Trampoline is 0x%x bytes long\n", trampoline_size);
fclose(fin);
prepare_real_mode_gdt();
char *cmdline = "verbose";
// Here we really smash our operating system!
memset(0x10000, 0, 0x10000);
memcpy((void*) 0x500, trampoline, trampoline_size);
memcpy((void*) 0x10000, real_mode, real_mode_size);
memcpy((void*) 0x1e000, cmdline, strlen(cmdline));
memcpy((void*) 0x100000, prot_mode, prot_mode_size);
((void (*)()) 0x500)();
free(trampoline);
free(real_mode);
free(prot_mode);
}
......
;; Inspired to https://wiki.osdev.org/Real_Mode
org 0x500
bits 32
;; Interrupts should already be disabled, but who knows...
cli
;; Load 16 bit GDT prepared by C code
lgdt [real_gdt]
jmp 0x10:disable_real_mode
bits 16
disable_real_mode:
;; Load 16 bit data segments
mov ax, 0x18
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
;; Disable protected mode (assume that paging is already disabled)
mov eax, cr0
and eax, 0xfffffffe
mov cr0, eax
jmp 0x0:real_mode
real_mode:
;; Reload segments and stack pointer
mov ax, 0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov sp, 0xe000
;; Reload IDT
lidt [real_idt]
;; Now load segments for Linux booting
mov ax, 0x1000
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov sp, 0xe000
;; Boot Linux
jmp 0x1020:0x0000
align 4
;; IDT data
real_idt:
dw 0x3ff
dd 0x00000000
align 4
real_gdt:
dw 31
dd 0x00000800
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment