|
@@ -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);
|
|
|
}
|