Orange'S 第三章第二节实验

这个实验没有完全按照书上的来,这个实验对比第一小节只是增加了栈段,有了栈,就可以安全的使用C函数了

desc.h 代码
#include <stdint.h>

// Type field
#define TYPE_DATA_RO          0
#define TYPE_DATA_RO_A        1
#define TYPE_DATA_RW          2
#define TYPE_DATA_RW_A        3
#define TYPE_DATA_RO_E        4
#define TYPE_DATA_RO_E_A      5
#define TYPE_DATA_RW_E        6
#define TYPE_DATA_RW_E_A      7
#define TYPE_CODE_XO          8
#define TYPE_CODE_XO_A        9
#define TYPE_CODE_XR          10
#define TYPE_CODE_XR_A        11
#define TYPE_CODE_XO_C        12
#define TYPE_CODE_XO_C_A      13
#define TYPE_CODE_XR_C        14
#define TYPE_CODE_XR_C_A      15

#define TYPE_SYS_TSS_16_A     1
#define TYPE_SYS_LDT          2
#define TYPE_SYS_TSS_16_B     3
#define TYPE_SYS_CALL_GATE_16 4
#define TYPE_SYS_TASK_GATE    5
#define TYPE_SYS_INT_GATE_16  6
#define TYPE_SYS_TRAP_GATE_16 7
#define TYPE_SYS_TSS_32_A     9
#define TYPE_SYS_TSS_32_B     11
#define TYPE_SYS_CALL_GATE_32 12
#define TYPE_SYS_INT_GATE_32  14
#define TYPE_SYS_TRAP_GATE_32 15

// S(descripor type) flag
#define DESC_TYPE_SYSTEM 0
#define DESC_TYPE_CODE   1
#define DESC_TYPE_DATA   1

// DPL(descriptor privilege level) field
#define DPL_0 0
#define DPL_1 1
#define DPL_2 2
#define DPL_3 3

// P(segment-present) flag
#define SEG_PRESENT     1
#define SEG_NOT_PRESENT 0

// D/B flag
#define CODE_32         1
#define CODE_16         0
#define DATA_32         1
#define DATA_16         0

// G(granularity) flag
#define G_BYTE    0
#define G_4K_BYTE 1

typedef struct __attribute__((packed)) {
    uint16_t limit;
    uint32_t base;
} gdtr_t;

typedef struct {
    uint16_t rpl:2;
    uint16_t ti:1;
    uint16_t index:13;
} seg_selector_t;

typedef struct {
    uint64_t limit_15_0:16;
    uint64_t base_23_0:24;
    uint64_t type:4;
    uint64_t s:1;
    uint64_t dpl:2;
    uint64_t p:1;
    uint64_t limit_19_16:4;
    uint64_t avl:1;
    uint64_t res:1;
    uint64_t db:1;
    uint64_t g:1;
    uint64_t base_31_24:8;
} seg_desc_t;

#define SEG_DESC(_base, _limit, _type, _s, _dpl, _p, _db, _g) { \
        .base_23_0 = (_base) & 0xffffff,         \
        .base_31_24 = ((_base) >> 24) & 0xff, \
        .limit_15_0 = (_limit) & 0xffff, \
            .limit_19_16 = ((_limit) >> 16) & 0xf, \
            .type = (_type), \
            .s = (_s), \
            .dpl = (_dpl), \
            .p = (_p), \
            .avl = 0, \
            .res = 0, \
            .db = (_db), \
            .g = (_g), \
}

desc.h 相对第一小节没有变化

gdt.c 这里文件定义了全局描述符表,即全局描述符表指针
#include "desc.h"

seg_desc_t gdt[] = {
    // null
    [0] = SEG_DESC(0, 0, 0, 0, 0, 0, 0, 0),
    // code32
    [1] = SEG_DESC(0x7c80, 0xff, TYPE_CODE_XO, DESC_TYPE_CODE, DPL_0, SEG_PRESENT, CODE_32, G_BYTE),
    // stack
    [2] = SEG_DESC(0x500000, 0xfffff, TYPE_DATA_RW, DESC_TYPE_DATA, DPL_0, SEG_PRESENT, DATA_32, G_BYTE),
    // video
    [3] = SEG_DESC(0xb8000, 0xffff, TYPE_DATA_RW, DESC_TYPE_DATA, DPL_0, SEG_PRESENT, DATA_32, G_BYTE),
};

gdtr_t gdtr = {
    .limit = sizeof(gdt)-1,
    .base = (uint32_t)&gdt,
};

gdt相对于第一小节,添加了一个栈段描述符,段基地址设为5M,为了演示突破1M的访问范围

boot.S 代码
#define CODE_SELECTOR  (1 << 3)
#define STACK_SELECTOR (2 << 3)
#define VIDEO_SELECTOR (3 << 3)

    .code16
    .section text16
    .globl _start
_start:
    cli

    # load gdtr
    lgdt gdtr

    # enable a20
    inb $0x92, %al
    orb $0b10, %al
    outb %al, $0x92

    # enable pm
    movl %cr0, %eax
    orl $0x01, %eax
    movl %eax, %cr0

    # jump to pm
    jmpl $CODE_SELECTOR, $0x0
    hlt

    .code32
    .section text32
    movw $STACK_SELECTOR, %ax
    movw %ax, %ss
    movw $VIDEO_SELECTOR, %ax
    movw %ax, %gs

    call main

boot.S 在进入保护模式后,只进行了栈段,和视频段的初始化,然后跳到main函数

main.c 代码
#include <stdint.h>

typedef union {
    struct {
        uint8_t c;       // al
        uint8_t attr;    // ah
    };
    uint16_t value;          // ax
} attr_char_t;

void display_char(attr_char_t ac, int pos)
{
    asm volatile("movw %0, %%gs:(%1)\n\t"
             :
             : "a"(ac.value), "D"(pos));
}

void display_attr_string(const char *str, uint8_t attr, int pos)
{
    for (; *str; ++str, pos+=2) {
        attr_char_t c = { *str, attr };
        display_char(c, pos);
    }
}

int main()
{
    display_attr_string("hello, world", 0x0c, 200);
}

c函数可以使用栈变量了,比如函数参数

#### boot.lds

OUTPUT_FORMAT(binary)
ENTRY(_start)

MEMORY {
       boot_region (RX) : org = 0x7c00, len = 512
}

SECTIONS {
     .text : {
         boot.o(text16)

         . = 64;
         gdt.o(.data*)

         . = 128;
         boot.o(text32)
         *(.text .rodata)

         . = 510;
         SHORT(0xaa55)
     } >boot_region

     /DISCARD/ : {
           *(*)
     }
}
Makefile
OBJECTS = boot.o gdt.o main.o
CFLAGS = -fno-pic -c
LDFLAGS = -Tboot.lds

a.img: boot.bin
    -rm a.img
    bximage -q -mode=create -fd=1.44M a.img
    dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc

boot.bin: $(OBJECTS) boot.lds
    ld $(LDFLAGS) $(OBJECTS) -o boot.bin
    ld $(LDFLAGS) $(OBJECTS) --oformat=elf32-i386 -o boot.elf  # for objdump

boot.o: boot.S
    gcc $(CFLAGS) boot.S

gdt.o: gdt.c desc.h
    gcc $(CFLAGS) gdt.c

main.o: main.c
    gcc $(CFLAGS) main.c

.PHONY: clean
clean:
    -rm $(OBJECTS) boot.bin boot.elf a.img
效果

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值