add lab answers
This commit is contained in:
26
labcodes_answer/lab2_result/boot/asm.h
Normal file
26
labcodes_answer/lab2_result/boot/asm.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#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__ */
|
||||
|
||||
107
labcodes_answer/lab2_result/boot/bootasm.S
Normal file
107
labcodes_answer/lab2_result/boot/bootasm.S
Normal file
@@ -0,0 +1,107 @@
|
||||
#include <asm.h>
|
||||
|
||||
# Start the CPU: switch to 32-bit protected mode, jump into C.
|
||||
# The BIOS loads this code from the first sector of the hard disk into
|
||||
# memory at physical address 0x7c00 and starts executing in real mode
|
||||
# with %cs=0 %ip=7c00.
|
||||
|
||||
.set PROT_MODE_CSEG, 0x8 # kernel code segment selector
|
||||
.set PROT_MODE_DSEG, 0x10 # kernel data segment selector
|
||||
.set CR0_PE_ON, 0x1 # protected mode enable flag
|
||||
.set SMAP, 0x534d4150
|
||||
|
||||
# start address should be 0:7c00, in real mode, the beginning address of the running bootloader
|
||||
.globl start
|
||||
start:
|
||||
.code16 # Assemble for 16-bit mode
|
||||
cli # Disable interrupts
|
||||
cld # String operations increment
|
||||
|
||||
# Set up the important data segment registers (DS, ES, SS).
|
||||
xorw %ax, %ax # Segment number zero
|
||||
movw %ax, %ds # -> Data Segment
|
||||
movw %ax, %es # -> Extra Segment
|
||||
movw %ax, %ss # -> Stack Segment
|
||||
|
||||
# Enable A20:
|
||||
# For backwards compatibility with the earliest PCs, physical
|
||||
# address line 20 is tied low, so that addresses higher than
|
||||
# 1MB wrap around to zero by default. This code undoes this.
|
||||
seta20.1:
|
||||
inb $0x64, %al # Wait for not busy
|
||||
testb $0x2, %al
|
||||
jnz seta20.1
|
||||
|
||||
movb $0xd1, %al # 0xd1 -> port 0x64
|
||||
outb %al, $0x64
|
||||
|
||||
seta20.2:
|
||||
inb $0x64, %al # Wait for not busy
|
||||
testb $0x2, %al
|
||||
jnz seta20.2
|
||||
|
||||
movb $0xdf, %al # 0xdf -> port 0x60
|
||||
outb %al, $0x60
|
||||
|
||||
probe_memory:
|
||||
movl $0, 0x8000
|
||||
xorl %ebx, %ebx
|
||||
movw $0x8004, %di
|
||||
start_probe:
|
||||
movl $0xE820, %eax
|
||||
movl $20, %ecx
|
||||
movl $SMAP, %edx
|
||||
int $0x15
|
||||
jnc cont
|
||||
movw $12345, 0x8000
|
||||
jmp finish_probe
|
||||
cont:
|
||||
addw $20, %di
|
||||
incl 0x8000
|
||||
cmpl $0, %ebx
|
||||
jnz start_probe
|
||||
finish_probe:
|
||||
|
||||
# Switch from real to protected mode, using a bootstrap GDT
|
||||
# and segment translation that makes virtual addresses
|
||||
# identical to physical addresses, so that the
|
||||
# effective memory map does not change during the switch.
|
||||
lgdt gdtdesc
|
||||
movl %cr0, %eax
|
||||
orl $CR0_PE_ON, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
# Jump to next instruction, but in 32-bit code segment.
|
||||
# Switches processor into 32-bit mode.
|
||||
ljmp $PROT_MODE_CSEG, $protcseg
|
||||
|
||||
.code32 # Assemble for 32-bit mode
|
||||
protcseg:
|
||||
# Set up the protected-mode data segment registers
|
||||
movw $PROT_MODE_DSEG, %ax # Our data segment selector
|
||||
movw %ax, %ds # -> DS: Data Segment
|
||||
movw %ax, %es # -> ES: Extra Segment
|
||||
movw %ax, %fs # -> FS
|
||||
movw %ax, %gs # -> GS
|
||||
movw %ax, %ss # -> SS: Stack Segment
|
||||
|
||||
# Set up the stack pointer and call into C. The stack region is from 0--start(0x7c00)
|
||||
movl $0x0, %ebp
|
||||
movl $start, %esp
|
||||
call bootmain
|
||||
|
||||
# If bootmain returns (it shouldn't), loop.
|
||||
spin:
|
||||
jmp spin
|
||||
|
||||
.data
|
||||
# Bootstrap GDT
|
||||
.p2align 2 # force 4 byte alignment
|
||||
gdt:
|
||||
SEG_NULLASM # null seg
|
||||
SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # code seg for bootloader and kernel
|
||||
SEG_ASM(STA_W, 0x0, 0xffffffff) # data seg for bootloader and kernel
|
||||
|
||||
gdtdesc:
|
||||
.word 0x17 # sizeof(gdt) - 1
|
||||
.long gdt # address gdt
|
||||
116
labcodes_answer/lab2_result/boot/bootmain.c
Normal file
116
labcodes_answer/lab2_result/boot/bootmain.c
Normal file
@@ -0,0 +1,116 @@
|
||||
#include <defs.h>
|
||||
#include <x86.h>
|
||||
#include <elf.h>
|
||||
|
||||
/* *********************************************************************
|
||||
* This a dirt simple boot loader, whose sole job is to boot
|
||||
* an ELF kernel image from the first IDE hard disk.
|
||||
*
|
||||
* DISK LAYOUT
|
||||
* * This program(bootasm.S and bootmain.c) is the bootloader.
|
||||
* It should be stored in the first sector of the disk.
|
||||
*
|
||||
* * The 2nd sector onward holds the kernel image.
|
||||
*
|
||||
* * The kernel image must be in ELF format.
|
||||
*
|
||||
* BOOT UP STEPS
|
||||
* * when the CPU boots it loads the BIOS into memory and executes it
|
||||
*
|
||||
* * the BIOS intializes devices, sets of the interrupt routines, and
|
||||
* reads the first sector of the boot device(e.g., hard-drive)
|
||||
* into memory and jumps to it.
|
||||
*
|
||||
* * Assuming this boot loader is stored in the first sector of the
|
||||
* hard-drive, this code takes over...
|
||||
*
|
||||
* * control starts in bootasm.S -- which sets up protected mode,
|
||||
* and a stack so C code then run, then calls bootmain()
|
||||
*
|
||||
* * bootmain() in this file takes over, reads in the kernel and jumps to it.
|
||||
* */
|
||||
|
||||
#define SECTSIZE 512
|
||||
#define ELFHDR ((struct elfhdr *)0x10000) // scratch space
|
||||
|
||||
/* waitdisk - wait for disk ready */
|
||||
static void
|
||||
waitdisk(void) {
|
||||
while ((inb(0x1F7) & 0xC0) != 0x40)
|
||||
/* do nothing */;
|
||||
}
|
||||
|
||||
/* readsect - read a single sector at @secno into @dst */
|
||||
static void
|
||||
readsect(void *dst, uint32_t secno) {
|
||||
// wait for disk to be ready
|
||||
waitdisk();
|
||||
|
||||
outb(0x1F2, 1); // count = 1
|
||||
outb(0x1F3, secno & 0xFF);
|
||||
outb(0x1F4, (secno >> 8) & 0xFF);
|
||||
outb(0x1F5, (secno >> 16) & 0xFF);
|
||||
outb(0x1F6, ((secno >> 24) & 0xF) | 0xE0);
|
||||
outb(0x1F7, 0x20); // cmd 0x20 - read sectors
|
||||
|
||||
// wait for disk to be ready
|
||||
waitdisk();
|
||||
|
||||
// read a sector
|
||||
insl(0x1F0, dst, SECTSIZE / 4);
|
||||
}
|
||||
|
||||
/* *
|
||||
* readseg - read @count bytes at @offset from kernel into virtual address @va,
|
||||
* might copy more than asked.
|
||||
* */
|
||||
static void
|
||||
readseg(uintptr_t va, uint32_t count, uint32_t offset) {
|
||||
uintptr_t end_va = va + count;
|
||||
|
||||
// round down to sector boundary
|
||||
va -= offset % SECTSIZE;
|
||||
|
||||
// translate from bytes to sectors; kernel starts at sector 1
|
||||
uint32_t secno = (offset / SECTSIZE) + 1;
|
||||
|
||||
// If this is too slow, we could read lots of sectors at a time.
|
||||
// We'd write more to memory than asked, but it doesn't matter --
|
||||
// we load in increasing order.
|
||||
for (; va < end_va; va += SECTSIZE, secno ++) {
|
||||
readsect((void *)va, secno);
|
||||
}
|
||||
}
|
||||
|
||||
/* bootmain - the entry of bootloader */
|
||||
void
|
||||
bootmain(void) {
|
||||
// read the 1st page off disk
|
||||
readseg((uintptr_t)ELFHDR, SECTSIZE * 8, 0);
|
||||
|
||||
// is this a valid ELF?
|
||||
if (ELFHDR->e_magic != ELF_MAGIC) {
|
||||
goto bad;
|
||||
}
|
||||
|
||||
struct proghdr *ph, *eph;
|
||||
|
||||
// load each program segment (ignores ph flags)
|
||||
ph = (struct proghdr *)((uintptr_t)ELFHDR + ELFHDR->e_phoff);
|
||||
eph = ph + ELFHDR->e_phnum;
|
||||
for (; ph < eph; ph ++) {
|
||||
readseg(ph->p_va & 0xFFFFFF, ph->p_memsz, ph->p_offset);
|
||||
}
|
||||
|
||||
// call the entry point from the ELF header
|
||||
// note: does not return
|
||||
((void (*)(void))(ELFHDR->e_entry & 0xFFFFFF))();
|
||||
|
||||
bad:
|
||||
outw(0x8A00, 0x8A00);
|
||||
outw(0x8A00, 0x8E00);
|
||||
|
||||
/* do nothing */
|
||||
while (1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user