Skip to content
Snippets Groups Projects
Commit 818d2971 authored by ivan.pavlovic's avatar ivan.pavlovic
Browse files

State machine done

parents
No related branches found
No related tags found
No related merge requests found
Makefile 0 → 100644
DISK=disk.raw
DISK_SIZE=256K
help:
@echo "Available targets:"
@echo " run_pv run paravirtualized guest"
@echo " run_phys run physical (native) guest"
@echo " vmm build VMM"
@echo " guest_pv build paravirtualized guest"
@echo " guest_phys build physical (native) guest"
@echo " clean delete VMM and guest"
@echo " clean_vmm delete VMM"
@echo " clean_guest delete guest"
disk:
qemu-img create -f raw ${DISK} ${DISK_SIZE}
run_pv: guest_pv vmm
./vmm/vmm ./guest/guest.bin ${DISK}
run_phys: guest_phys vmm
./vmm/vmm ./guest/guest.bin ${DISK}
guest_pv:
$(MAKE) -C guest PV=1 OUT=guest.bin
guest_phys:
$(MAKE) -C guest PV=0 OUT=guest.bin
vmm:
$(MAKE) -C vmm OUT=vmm
clean: clean_vmm clean_guest
clean_vmm:
$(MAKE) -C vmm clean OUT=vmm
clean_guest:
$(MAKE) -C guest clean OUT=guest.bin
.PHONY: run_pv run_phys guest_pv guest_phys vmm clean clean_vmm clean_guest
disk.raw 0 → 100644
File added
BAREMETAL_FLAGS=-m32 -march=i386 -ffreestanding -nostdlib -fno-builtin -fno-stack-protector -fno-pie -static
CC=gcc -std=gnu17 $(BAREMETAL_FLAGS) -Wall -Wextra -MMD -Ishared -I../.. -I..
CC+=-DPV=$(PV)
LD=gcc -Tguest.ld $(BAREMETAL_FLAGS)
C_SRCS=$(shell find . -name "*.c")
C_OBJS=$(C_SRCS:.c=.o)
C_DEPS=$(C_OBJS:%.o=%.d)
ASM_SRCS=$(shell find . -name "*.s")
ASM_OBJS=$(ASM_SRCS:.s=.o)
$(OUT): $(C_OBJS) $(ASM_OBJS)
$(LD) $^ -o $@
%.o: %.c
$(CC) -c $< -o $@
%.o: %.s
nasm -f elf32 $< -o $@
clean:
rm -f $(C_OBJS) $(ASM_OBJS) $(C_DEPS) *.o *.d $(OUT)
.PHONY: clean
-include $(C_DEPS)
#ifndef _DESCRIPTORS_H_
#define _DESCRIPTORS_H_
// Privilege levels
#define DPL_USER 0x3
#define DPL_KERNEL 0x0
// Selectors
//#define LDT_SELECTOR 0x4
// Descriptor types for code and data segments
#define TYPE_DATA_RO 1 // read-only
#define TYPE_DATA_RW 3 // read-write
// Stack segments are data segments which must be read/write segments. Loading the
// SS register with a segment selector for a nonwritable data segment generates a
// general-protection exception (#GP). If the size of a stack segment needs to be
// changed dynamically, the stack segment can be an expand-down data segment
// (expansion-direction flag set). Here, dynamically changing the segment limit causes
// stack space to be added to the bottom of the stack. If the size of a stack segment is
// intended to remain static, the stack segment may be either an expand-up or expand-down type.
#define TYPE_DATA_RW_EXPAND_DOWN 6 // stack segment type
#define TYPE_CODE_EXECONLY 9
#define TYPE_CODE_EXECREAD 11
// Descriptor types for system segments and gates
#define TYPE_LDT 2
#define TYPE_TASK_GATE 5
#define TYPE_TSS 9
#define TYPE_CALL_GATE 12
#define TYPE_TRAP_GATE 15
#define TYPE_INTERRUPT_GATE 14
#endif
File added
CODE_SELECTOR equ 0x08
DATA_SELECTOR equ 0x10
extern guest_main
section .entrypoint
[BITS 16]
cli ; disable hardware interrupts (since no IDT loaded yet)
lgdt [gdt_descriptor] ; load GDT (see segments defined after gdt_start below)
; switch to protected mode (32-bits mode)
mov eax,cr0
or eax,1 ; set PE (Protection Enable) bit in CR0 (Control Register 0)
mov cr0,eax
jmp CODE_SELECTOR:flush ; far jump [selector:offset] to load code segment (cs) with code descriptor in GDT
flush:
[BITS 32]
mov ax,DATA_SELECTOR ; update data (ds), stack (sp) and extra (es) segments with data descriptor in GDT
mov ds,ax
mov ss,ax
mov es,ax
call guest_main ; call guest C code entrypoint
@forever:
hlt ; halt the CPU
jmp @forever
; Setup a GDT table to identity map the full 4GB address space (32 bits)
gdt_start: ; the GDT table starts here
gdt_null: ; 1st descriptor: NULL descriptor (required)
dd 0
dd 0
gdt_code: ; 2nd descriptor: code descriptor: base=0, limit=0xFFFFF (4GB)
dw 0xFFFF ; limit (bits 0-15)
dw 0 ; base (bits 0-15)
db 0 ; base (bits 16-23)
db 10011001b ; bit 7: P: present in memory
; bits 5-6: DPL: privilege level (ring level)
; bit 4: S: 1 for segments, 0 for system (TSS, LDT, gates)
; bit 0-3: Type: 1001b (9) for code exec only
db 11001111b ; bits 4-7: flags:
; bit 7: G: granularity (0=1 byte, 1=4KB)
; bit 6: D: 1 for 32-bit code and data segments; 0 for system (TSS, LDT, gate)
; bit 5: must be 0
; bit 4: available for use
; bits 0-3: limit (bits 16-19)
db 0 ; base (bits 24-31)
gdt_data: ; 3rd descriptor: data descriptor: base=0, limit=0xFFFFF (4GB)
dw 0xFFFF ; limit (bits 0-15)
dw 0 ; base (bits 0-15)
db 0 ; base (bits 16-23)
db 10010011b ; bit 7: P: present in memory
; bits 5-6: DPL: privilege level (ring level)
; bit 4: S: 1 for segments, 0 for system (TSS, LDT, gates)
; bit 0-3: Type: 0011b (3) data read/write
db 11001111b ; bits 4-7: flags:
; bit 7: G: granularity (0=1 byte, 1=4KB)
; bit 6: D: 1 for 32-bit code and data segments; 0 for system (TSS, LDT, gate)
; bit 5: must be 0
; bit 4: available for use
; bits 0-3: limit (bits 16-19)
db 0 ; base (bits 24-31)
gdt_end:
gdt_descriptor: ; descriptor pointing to the GDT (required by the lgdt instruction)
dw gdt_end - gdt_start - 1 ; GDT size minus 1
dd gdt_start ; address of the GDT table
File added
OUTPUT_FORMAT("binary")
SECTIONS {
. = 0; /* first section located at address 0 */
.entrypoint ALIGN(4): /* entry point: must be located at 0 */
{
*(.entrypoint)
}
.text ALIGN(4) : /* code */
{
*(.text*)
}
.rodata ALIGN(4) : /* read-only data */
{
*(.rodata*)
}
.data ALIGN(4) : /* initialized data */
{
*(.data*)
}
.bss ALIGN(4) : /* unitialized data */
{
*(COMMON)
*(.bss*)
}
}
#include <stdint.h>
#include "idt.h"
#include "utils.h"
#include "pmio.h"
#include "../shared/hypercall_params.h"
#include "x86.h"
#define SHARED_STORAGE_ADDRESS 0xC0000000
// If PV == 1 => uses paravirtualized drivers (when available)
// If PV == 0 => uses physical (hardware) drivers (when available)
#if PV == 1
#define timer_sleep timer_sleep_pv
#else
#define timer_sleep timer_sleep_phys
#endif
void timer_sleep_pv(int usec) {
hyper_timer_sleep_params_t *timer_sleep_params = (hyper_timer_sleep_params_t*)(SHARED_STORAGE_ADDRESS);
timer_sleep_params->us = usec;
outb(0xABBA, 2);
}
void timer_sleep_phys(int usec) {
outw(0x43, 20);
outd(0x40, (uint32_t)usec);
}
void console_pv(char* msg){
hyper_console_params_t *console_params = (hyper_console_params_t*)(SHARED_STORAGE_ADDRESS);
console_params->msg = (uint64_t)(uint32_t)msg;
outb(0xABBA, 1);
}
void affichage_pv(uint32_t width, uint32_t height){
hyper_display_params_t *display_params = (hyper_display_params_t*)(SHARED_STORAGE_ADDRESS);
display_params->width = width;
display_params->height = height;
outb(0xABBA, 3);
}
void write_disk(uint32_t sector_idx, void *data){
hyper_disk_params_t *disk_params = (hyper_disk_params_t*)(SHARED_STORAGE_ADDRESS);
disk_params->sector_idx = sector_idx;
disk_params->data = (uint64_t)(uint32_t)data;
outb(0xABBA, 4);
}
void guest_main() {
idt_init(); // Initialize interrupt subsystem
sti(); // Enable hardware interrupts
// console_pv("Salut test guest OS\n");
// char data[512] = "Salut sa va mon pote !!!";
// write_disk(1, data);
// console_pv("Disk written\n");
// console_pv("Débloquage du display!\n");
// affichage_pv(400, 300);
console_pv("Attente de 100000\n");
// timer_sleep(10000000);
timer_sleep_phys(10000000);
console_pv("Après attente!!\n");
}
guest_main.o: guest_main.c idt.h utils.h pmio.h \
../shared/hypercall_params.h x86.h
File added
#ifndef _IDE_H_
#define _IDE_H_
#define SECTOR_SIZE 512
// Write a sector.
// Implement a device driver for the true physical hardware.
void ide_write_sector_phys(int sector_idx, void *data);
#endif
#include <stdint.h>
#include "ide.h"
#include "shared/ide_regs.h"
#include "../pmio.h"
// IDE controler is programmed in PMIO.
/**
* Wait for the disk drive to be ready.
*/
static void wait_drive() {
while ((inb(IDE_STATUS_REG) & 0xC0) != 0x40);
}
/**
* Prepare the disk drive for read/write at the specified sector in 28-bit LBA mode.
* @param sector the sector to read or write
*/
static void pio_prepare(int sector) {
wait_drive();
outb(IDE_DATA_BASE_REG+2, 1); // sector count
outb(IDE_DATA_BASE_REG+3, sector & 0xff); // send bits 0-7 of LBA
outb(IDE_DATA_BASE_REG+4, (sector >> 8) & 0xff); // send bits 8-15 of LBA
outb(IDE_DATA_BASE_REG+5, (sector >> 16) & 0xff); // send bits 16-23 of LBA
outb(IDE_DATA_BASE_REG+6, ((sector >> 24) & 0x0f) | 0xe0); // send bits 24-27 of LBA + set LBA mode; 0xe0 = 11100000b;
}
/**
* Read a sector from the first disk.
* @param first sector to read (0-indexed)
* @param dst address to store to read data
* Based on the assembly code at http://wiki.osdev.org/ATA_read/write_sectors
*/
void ide_write_sector_phys(int sector, void *data) {
pio_prepare(sector);
outb(IDE_CMD_REG, 0x30); // command port: write with retry
wait_drive();
uint16_t *d = (uint16_t *)data;
for (int i = 0; i < SECTOR_SIZE/2; i++) {
outw(IDE_DATA_BASE_REG, *d);
d++;
}
}
ide/ide_phys.o: ide/ide_phys.c ide/ide.h ../shared/ide_regs.h \
ide/../pmio.h
File added
#include "idt.h"
#include "utils.h"
#include "descriptors.h"
#include "x86.h"
#define GDT_KERNEL_CODE_SELECTOR 0x08
// Structure of an IDT descriptor. There are 3 types of descriptors:
// task-gates, interrupt-gates, trap-gates.
// See 5.11 of Intel 64 & IA32 architectures software developer's manual for more details.
// For task gates, offset must be 0.
typedef struct idt_entry_st {
uint16_t offset15_0; // only used by trap and interrupt gates
uint16_t selector; // segment selector for trap and interrupt gates; TSS segment
// selector for task gates
uint16_t reserved : 8;
uint16_t type : 5;
uint16_t dpl : 2;
uint16_t p : 1;
uint16_t offset31_16; // only used by trap and interrupt gates
} __attribute__((packed)) idt_entry_t;
// Structure describing a pointer to the IDT gate table.
// This format is required by the lidt instruction.
typedef struct idt_ptr_st {
uint16_t limit; // Limit of the table (ie. its size)
uint32_t base; // Address of the first entry
} __attribute__((packed)) idt_ptr_t;
// Gates table
static idt_entry_t idt[256];
static idt_ptr_t idt_ptr;
// Defined in idt_asm.s
void idt_load(idt_ptr_t *idt_ptr);
// Build and return an IDT entry.
// selector is the code segment selector to access the ISR
// offset is the address of the ISR (for task gates, offset must be 0)
// type indicates the IDT entry type
// dpl is the privilege level required to call the associated ISR
static idt_entry_t idt_build_entry(uint16_t selector, uint32_t offset, uint8_t type, uint8_t dpl) {
idt_entry_t entry;
entry.offset15_0 = offset & 0xffff;
entry.selector = selector;
entry.reserved = 0;
entry.type = type;
entry.dpl = dpl;
entry.p = 1;
entry.offset31_16 = (offset >> 16) & 0xffff;
return entry;
}
// Low level handler defined in idt_asm.s
void _irq0();
// IRQ handler
void irq_handler(uint32_t irq_number) {
}
void idt_init() {
idt_ptr.limit = sizeof(idt)-1;
idt_ptr.base = (uint32_t)&idt;
// Clear up all entries
memset(idt, 0, sizeof(idt));
idt[0] = idt_build_entry(GDT_KERNEL_CODE_SELECTOR, (uint32_t)_irq0, TYPE_INTERRUPT_GATE, DPL_KERNEL);
idt_load(&idt_ptr);
}
idt.o: idt.c idt.h utils.h descriptors.h x86.h
#ifndef _IDT_H_
#define _IDT_H_
void idt_init();
#endif
File added
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment