注意:这篇文章上次更新于504天前,文章内容可能已经过时。
硬件和程序员的约定
CPU Reset 后寄存器会有确定的初始状态
- EIP = 0x0000fff0
- CR0 = 0x60000010
- 处理器处于 16-bit 模式
- EFLAGS = 0x00000002
- interrupt disabled
Reset 后处理器从固定地址(Reset Vector)启动
- MIPS: 0xbfc000000
- Specification 规定
- ARM: 0x00000000
- Specification 规定
- 允许配置 Reset Vector Base Address Register
- RISC-V: Implementation defined
- 给厂商最大程度的自由
Demo: firmware
mbr.img: mbr.S
gcc -ggdb -c $<
ld mbr.o -Ttext 0x7c00
objcopy -S -O binary -j .text a.out $@
run: mbr.img
qemu-system-x86_64 $<
debug: mbr.img
qemu-system-x86_64 -s -S $< & # Run QEMU in background
gdb -x init.gdb # RTFM: gdb (1)
clean:
rm -f *.img *.o a.out
#define SECT_SIZE 512
.code16 // 16-bit assembly
// Entry of the code
.globl _start
_start:
lea (msg), %si // R[si] = &msg;
again:
movb (%si), %al // R[al] = *R[si]; <--+
incw %si // R[si]++; |
orb %al, %al // if (!R[al]) |
jz done // goto done; --+ |
movb $0x0e, %ah // R[ah] = 0x0e; | |
movb $0x00, %bh // R[bh] = 0x00; | |
int $0x10 // bios_call(); | |
jmp again // goto again; ---+---+
// |
done: // |
jmp . // goto done; <---+
// Data: const char msg[] = "...";
msg:
.asciz "This is a baby step towards operating systems!\r\n"
// Magic number for bootable device
.org SECT_SIZE - 2
.byte 0x55, 0xAA
# Kill process (QEMU) on gdb exits
define hook-quit
kill
end
# Connect to remote
target remote localhost:1234
file a.out
break *0x7c00
layout src
continue
实现最小的操作系统
NAME := hello
SRCS := hello.c
export ARCH := x86_64-qemu
include $(AM_HOME)/Makefile
#include <am.h>
#include <klib.h>
#include <klib-macros.h>
typedef union task {
struct {
const char *name;
union task *next;
void (*entry)(void *);
Context *context;
};
uint8_t stack[8192];
} Task;
Task *current;
void func(void *arg) {
while (1) {
putch(*(char *)arg);
for (int volatile i = 0; i < 100000; i++) ;
}
}
Task tasks[] = {
{ .name = "a", .entry = func },
{ .name = "b", .entry = func },
};
Context *on_interrupt(Event ev, Context *ctx) {
if (!current) {
current = &tasks[0];
} else {
current->context = ctx;
}
return (current = current->next)->context;
}
int main() {
cte_init(on_interrupt); // call on_interrupt() on traps/interrupts
for (int i = 0; i < LENGTH(tasks); i++) {
Task *task = &tasks[i];
Area stack = (Area) { &task->context + 1, task + 1 };
task->context = kcontext(stack, task->entry, (void *)task->name);
task->next = &tasks[(i + 1) % LENGTH(tasks)];
}
iset(true); // Enable external interrupts (timer, I/O, ...)
yield(); // Trap
}
#include <am.h>
#define ESC "\033["
#define RED ESC "01;31m"
#define CLR ESC "0m"
const char *MESSAGE = RED "Hello, OS World\n" CLR;
int main() {
for (const char *s = MESSAGE; *s; s++) {
putch(*s); // Prints to platform-dependent debug console
}
}