Skip to content

Commit

Permalink
Merge branch 'writing-os-in-1000-lines'
Browse files Browse the repository at this point in the history
  • Loading branch information
rhysd committed Sep 22, 2023
2 parents 78b484f + ca747fd commit ba75243
Show file tree
Hide file tree
Showing 17 changed files with 1,376 additions and 0 deletions.
7 changes: 7 additions & 0 deletions writing_os_in_1000_lines/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
*.map
*.tar
*.o
*.elf
*.bin
*.log
*.pcap
29 changes: 29 additions & 0 deletions writing_os_in_1000_lines/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
CC := clang
CFLAGS := -std=c11 -O2 -g3 -Wall -Wextra --target=riscv32 -ffreestanding -nostdlib
OBJCOPY := llvm-objcopy
FS := $(wildcard disk/*)

all: kernel.elf shell.bin.o disk.tar opensbi-riscv32-generic-fw_dynamic.bin

kernel.elf: kernel.ld kernel.c kernel.h common.c common.h shell.bin.o
$(CC) $(CFLAGS) -Wl,-Tkernel.ld -Wl,-Map=kernel.map -o kernel.elf \
kernel.c common.c shell.bin.o

shell.elf: user.ld shell.c user.c user.h common.c common.h
$(CC) $(CFLAGS) -Wl,-Tuser.ld -Wl,-Map=shell.map -o shell.elf \
shell.c user.c common.c
shell.bin: shell.elf
$(OBJCOPY) --set-section-flags .bss=alloc,contents -O binary shell.elf shell.bin
shell.bin.o: shell.bin
$(OBJCOPY) -Ibinary -Oelf32-littleriscv shell.bin shell.bin.o

disk.tar: $(FS)
(cd ./disk && tar cf ../disk.tar --format=ustar ./*.txt)

opensbi-riscv32-generic-fw_dynamic.bin:
curl -LO https://github.com/qemu/qemu/raw/v8.0.4/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin

clean:
rm *.elf *.map *.bin *.o disk.tar

.PHONY: clean all
48 changes: 48 additions & 0 deletions writing_os_in_1000_lines/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Writing OS in 1000 lines
========================

This is a very small toy OS written in about 1000 lines following the below guide.

https://operating-system-in-1000-lines.vercel.app/ja/welcome

```console
$ tokei *.c *.h [Husky.local][09/22 23:09]
===============================================================================
Language Files Lines Code Comments Blanks
===============================================================================
C 4 948 715 108 125
C Header 3 247 206 15 26
===============================================================================
Total 7 1195 921 123 151
===============================================================================
```

### Repository structure

```
├── disk/ - Filesystem content
├── common.c - Common libraries shared by both kernel and (e.g. `printf`, `memset`)
├── common.h - Common libraries shared by both kernel and (structs and constants)
├── kernel.c - Kernel: Process management, system call, device driver, filesystem
├── kernel.h - Kernel: structs and constants
├── kernel.ld - Kernel: Linker script (definition of memory layout)
├── shell.c - Command line shell
├── user.c - Libraries for user land: Functions for using system calls, ...
├── user.h - Libraries for user land: Structs and constants
├── user.ld - User land: Linker script (definition of memory layout)
├── Makefile - Build script
└── run.sh - Script to run kernel with QEMU
```

### How to build

```sh
source env.sh # For macOS
make
```

### How to run QEMU

```sh
./run.bash
```
116 changes: 116 additions & 0 deletions writing_os_in_1000_lines/common.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#include "common.h"

void putchar(char ch);

void *memset(void *buf, char c, size_t n) {
uint8_t *p = (uint8_t *)buf;
while (n--) {
*p++ = c;
}
return buf;
}

void *memcpy(void *dst, void const *src, size_t n) {
uint8_t *d = (uint8_t *)dst;
uint8_t const *s = (uint8_t const *)src;
while (n--) {
*d++ = *s++;
}
return dst;
}

char *strcpy(char *dst, char const *src) {
char *d = dst;
while (*src) {
*d++ = *src++;
}
*d = '\0';
return dst;
}

int strcmp(char const *s1, char const *s2) {
while (*s1 && *s2 && *s1 == *s2) {
s1++;
s2++;
}
return *s1 - *s2;
}

int strlen(char const *s) {
for (int i = 0;; i++) {
if (s[i] == '\0') {
return i;
}
}
}

bool startswith(char const *heystack, char const *needle) {
for (int i = 0;; i++) {
char const h = heystack[i], n = needle[i];
if (n == '\0') {
return true;
}
if (h != n) {
return false;
}
}
}

void printf(char const *fmt, ...) {
va_list vargs;
va_start(vargs, fmt);

while (*fmt) {
if (*fmt == '%') {
if (*(fmt + 1)) {
fmt++;
}
switch (*fmt) {
case '%':
putchar('%');
break;
case 's': {
char const *s = va_arg(vargs, const char *);
while (*s) {
putchar(*s);
s++;
}
break;
}
case 'd': {
int value = va_arg(vargs, int);
if (value < 0) {
putchar('-');
value = -value;
}

int divisor = 1;
while (value / divisor > 9) {
divisor *= 10;
}

while (divisor > 0) {
putchar('0' + value / divisor);
value %= divisor;
divisor /= 10;
}

break;
}
case 'x': {
int value = va_arg(vargs, int);
for (int i = 7; i >= 0; i--) {
int nibble = (value >> (i * 4)) & 0xf;
putchar("0123456789abcdef"[nibble]);
}
}
}
} else {
putchar(*fmt);
}

fmt++;
}

va_end(vargs);
}
35 changes: 35 additions & 0 deletions writing_os_in_1000_lines/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

typedef int bool;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef uint32_t size_t;
typedef uint32_t paddr_t; // Physical address type
typedef uint32_t vaddr_t; // Virtual address type

#define true 1
#define false 0
#define NULL ((void *)0)
#define align_up(value, align) __builtin_align_up(value, align) // Get next aligned value
#define is_aligned(value, align) __builtin_is_aligned(value, align)
#define offsetof(type, member) __builtin_offsetof(type, member) // Get struct member byte offset
#define va_list __builtin_va_list
#define va_start __builtin_va_start
#define va_end __builtin_va_end
#define va_arg __builtin_va_arg

#define SYSCALL_PUTCHAR 1
#define SYSCALL_GETCHAR 2
#define SYSCALL_EXIT 3
#define SYSCALL_READFILE 4
#define SYSCALL_WRITEFILE 5

void *memset(void *buf, char c, size_t n);
void *memcpy(void *dst, void const *src, size_t n);
char *strcpy(char *dst, char const *src);
int strcmp(char const *s1, char const *s2);
int strlen(char const *s);
bool startswith(char const *heystack, char const *needle);
void printf(char const *fmt, ...);
1 change: 1 addition & 0 deletions writing_os_in_1000_lines/disk/bowwow.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bow wow!
Empty file.
1 change: 1 addition & 0 deletions writing_os_in_1000_lines/disk/hello.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello world from text file in the filesystem!
3 changes: 3 additions & 0 deletions writing_os_in_1000_lines/env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

export PATH="/usr/local/opt/llvm/bin:$PATH"
Loading

0 comments on commit ba75243

Please sign in to comment.