ucore lab1分proj代码分析(持续更新)

因为我想把ucore 的课程以及代码好好学习一年,我给自己的时间长达一年,而且对于lab1而言,其中的所有代码,当时编写人员都整整写了一个月,我不能马马虎虎看完觉得自己半个月看不懂就放弃或者到下一个lab,这样,底子不牢,地动山摇。

所以,我就借着平时的空间时间或者非必要工作时间,非抠也把这个课程所有代码给抠完。

在这个过程中,我相信我一定会有很大的进步和成长。

proj1

结构图

在这里插入图片描述

涉及到的知识点

boot部分

asm.h部分

#ifndef __BOOT_ASM_H__                                                                                                                                       
#define __BOOT_ASM_H__

/* Assembler macros to create x86 segments */

/* Normal segment */
#define SEG_NULLASM                                             \
    .word 0, 0;                                                 \
    .byte 0, 0, 0, 0
/*

*/
#define SEG_ASM(type,base,lim)                                  \
    .word (((lim) >> 12) & 0xffff), ((base) & 0xffff);          \
    .byte (((base) >> 16) & 0xff), (0x90 | (type)),             \
        (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff)


/* Application segment type bits */
#define STA_X       0x8     // Executable segment
#define STA_E       0x4     // Expand down (non-executable segments)
#define STA_C       0x4     // Conforming code segment (executable only)
#define STA_W       0x2     // Writeable (non-executable segments)
#define STA_R       0x2     // Readable (executable segments)
#define STA_A       0x1     // Accessed

#endif /* !__BOOT_ASM_H__ */

GDT加载过程分析

# Bootstrap GDT
.p2align 2                                # force 4 byte alignment 向后移动位置计数器置为4字节的倍数 为了内存对齐
gdt:
  SEG_NULLASM                             # null seg
  SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff)   # code seg 可执行段或可读可执行段
  SEG_ASM(STA_W, 0x0, 0xffffffff)         # data seg 可写但是不可执行段

gdtdesc:
  .word   (gdtdesc - gdt - 1)             # sizeof(gdt) - 1 gdt表的长度,以字节为单位 这里不太懂为什么这样写
  .long   gdt                             # address gdt .long后面的参数为gdt运行时生成的值,即gdt表的地址

在x86中地址为32位即4字节,.p2align 2 就是将位置计数器移动到4字节的倍数,如果已经是4字节的倍数则不会发生变化。全局描述符号的第一段为空段,这是intel的规定。后两个段是数据段和代码段,最大限长为4GB。下图为GDT的结构。
在这里插入图片描述
段描述符的定义:

struct segdesc {
  uint lim_15_0 : 16;  // Low bits of segment limit
  uint base_15_0 : 16; // Low bits of segment base address
  uint base_23_16 : 8; // Middle bits of segment base address
  uint type : 4;       // Segment type (see STS_ constants)
  uint s : 1;          // 0 = system, 1 = application
  uint dpl : 2;        // Descriptor Privilege Level
  uint p : 1;          // Present
  uint lim_19_16 : 4;  // High bits of segment limit
  uint avl : 1;        // Unused (available for software use)
  uint rsv1 : 1;       // Reserved
  uint db : 1;         // 0 = 16-bit segment, 1 = 32-bit segment
  uint g : 1;          // Granularity: limit scaled by 4K when set
  uint base_31_24 : 8; // High bits of segment base address
 };

在整个系统中GDT只有一张,GDT可以被放在内存的任何位置,但CPU必须知道GDT的入口,也就是基地址放在哪里,Intel的设计者门提供了一个寄存器GDTR用来存放GDT的入口地址,程序员将GDT设定在内存中某个位置之后,可以通过LGDT指令将GDT的入口地址装入此寄存器,从此以后,CPU就根据此寄存器中的内容作为GDT的入口来访问GDT了。GDTR中存放的是GDT在内存中的基地址和其表长界限。

关于SEG_ASM的定义在ASM.h中

//
// assembler macros to create x86 segments
//
//定义了一个空段描述符
//.word表示就地生成一个字大小的数,.byte就地生成一个字节的数
#define SEG_NULLASM                                             \
        .word 0, 0;                                             \
        .byte 0, 0, 0, 0

//以type,base,lim为参数定义一个段描述符,0xC0=11000000,其中
//第一个1对应于段描述符中的G位,置1表示段界限以4KB为单位
//第二个1对应于段描述符中的D位,置1表示是保护模式下的段描述符
//关于段描述符的格式定义在mmu.h中
// The 0xC0 means the limit is in 4096-byte units
// and (for executable segments) 32-bit mode.
#define SEG_ASM(type,base,lim)                                \
        .word (((lim) >> 12) & 0xffff), ((base) & 0xffff);      \
        .byte (((base) >> 16) & 0xff), (0x90 | (type)),         \
                (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff)

#define STA_X     0x8       // Executable segment可执行段
#define STA_E     0x4       // Expand down (non-executable segments)非可执行段
#define STA_C     0x4       // Conforming code segment (executable only)只能执行的段
#define STA_W     0x2       // Writeable (non-executable segments)可写但是不可执行的段
#define STA_R     0x2       // Readable (executable segments)可读可执行的段
#define STA_A     0x1       // Accessed表明描述符是否已被访问,把选择字装入段寄存器时,标记为1

关于这段代码,lgdt指令是将GDT入口地址存到gdtdesc寄存器里,下面三行是修改cr0寄存器的值。gdt在内存中的位置在定义的时候就确定了。

lgdt    gdtdesc
  movl    %cr0, %eax
  orl     $CR0_PE, %eax
  movl    %eax, %cr0

bootmain.c 部分

#include <types.h>
#include <x86.h>

#define COM1            0x3F8
#define CRTPORT         0x3D4
#define LPTPORT         0x378
#define COM_TX          0           // Out: Transmit buffer (DLAB=0)
#define COM_LSR         5           // In:  Line Status Register
#define COM_LSR_TXRDY   20          // Transmit buffer avail

static uint16_t *crt = (uint16_t *) 0xB8000;        // CGA memory

/* stupid I/O delay routine necessitated by historical PC design flaws */
static void
delay(void) {
    inb(0x84);
    inb(0x84);
    inb(0x84);
    inb(0x84);
}

/* lpt_putc - copy console output to parallel port */
static void
lpt_putc(int c) {
    int i;
    for (i = 0; !(inb(LPTPORT + 1) & 0x80) && i < 12800; i ++) {
        delay();
    }
    outb(LPTPORT + 0, c);
    outb(LPTPORT + 2, 0x08 | 0x04 | 0x01);
    outb(LPTPORT + 2, 0x08);
}

/* cga_putc - print character to console */
static void
cga_putc(int c) {
    int pos;

    // cursor position: col + 80*row.
    outb(CRTPORT, 14);
    pos = inb(CRTPORT + 1) << 8;
    outb(CRTPORT, 15);
    pos |= inb(CRTPORT + 1);

    if (c == '\n') {
        pos += 80 - pos % 80;
    }
    else {
        crt[pos ++] = (c & 0xff) | 0x0700;
    }

    outb(CRTPORT, 14);
    outb(CRTPORT + 1, pos >> 8);
    outb(CRTPORT, 15);
    outb(CRTPORT + 1, pos);
}

/* serial_putc - copy console output to serial port */
static void
serial_putc(int c) {
    int i;
    for (i = 0; !(inb(COM1 + COM_LSR) & COM_LSR_TXRDY) && i < 12800; i ++) {
        delay();
    }
    outb(COM1 + COM_TX, c);
}

/* cons_putc - print a single character to console*/
static void
cons_putc(int c) {
    lpt_putc(c);
    cga_putc(c);
    serial_putc(c);
}

/* cons_puts - print a string to console */
static void
cons_puts(const char *str) {
    while (*str != '\0') {
        cons_putc(*str ++);
    }
}

/* bootmain - the entry of bootloader */
void
bootmain(void) {
    cons_puts("This is a bootloader: Hello world!!");

    /* do nothing */
    while (1);
}

libs部分代码分析

types.h

在这里插入代码片#ifndef __LIBS_TYPES_H__
#define __LIBS_TYPES_H__

#ifndef NULL
#define NULL ((void *)0)
#endif

/* Represents true-or-false values */
typedef int bool;

/* Explicitly-sized versions of integer types */
typedef char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;

#endif /* !__LIBS_TYPES_H__ */

x86.h

#ifndef __LIBS_X86_H__
#define __LIBS_X86_H__

#include <types.h>

#define barrier() __asm__ __volatile__ ("" ::: "memory")

static inline uint8_t inb(uint16_t port) __attribute__((always_inline));
static inline void outb(uint16_t port, uint8_t data) __attribute__((always_inline));

static inline uint8_t
inb(uint16_t port) {
    uint8_t data;
    asm volatile ("inb %1, %0" : "=a" (data) : "d" (port) : "memory");
    return data;
}

static inline void
outb(uint16_t port, uint8_t data) {
    asm volatile ("outb %0, %1" :: "a" (data), "d" (port) : "memory");
}

#endif /* !__LIBS_X86_H__ */
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值