Skip to content

Commit

Permalink
Add support for clang (#176)
Browse files Browse the repository at this point in the history
* Initial clang support.

* Fix clang PF bug

* Fixed building with DEBUG=1, and update tests to use toolchain compiler

* Requested changes

* Potential formatting fix

* Update Building.md

* Update README.md (#180)

---------

Co-authored-by: Ivan Gualandri <[email protected]>
Co-authored-by: Ivan G <[email protected]>
  • Loading branch information
3 people authored Sep 24, 2023
1 parent a4ba1d0 commit 058c469
Show file tree
Hide file tree
Showing 25 changed files with 90 additions and 136 deletions.
42 changes: 24 additions & 18 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,21 @@ ARCH_PREFIX := x86_64-elf
ASM_COMPILER := nasm
QEMU_SYSTEM := qemu-system-x86_64

ifeq ($(TOOLCHAIN), gcc)
X_CC = $(ARCH_PREFIX)-gcc
X_LD = $(ARCH_PREFIX)-ld
else ifeq ($(TOOLCHAIN), clang)
X_CC = clang
X_LD = ld.lld
else
$(error "Unknown compiler toolchain")
endif

C_DEBUG_FLAGS := -g \
-DDEBUG=1

ASM_DEBUG_FLAGS := -g \
-F dwarf
-F dwarf
ASM_FLAGS := -f elf64
ASM_FLAGS += $(DEF_FLAGS)

Expand Down Expand Up @@ -39,6 +52,8 @@ run: $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME)
$(QEMU_SYSTEM) -cdrom $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME)

debug: DEBUG=1
debug: CFLAGS += $(C_DEBUG_FLAGS)
debug: ASM_FLAGS += $(ASM_DEBUG_FLAGS)
debug: $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME)
# qemu-system-x86_64 -monitor unix:qemu-monitor-socket,server,nowait -cpu qemu64,+x2apic -cdrom build/DreamOs64.iso -serial file:dreamos64.log -m 1G -d int -no-reboot -no-shutdown
$(QEMU_SYSTEM) -monitor unix:qemu-monitor-socket,server,nowait -cpu qemu64,+x2apic -cdrom $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME) -serial stdio -m 2G -no-reboot -no-shutdown
Expand All @@ -54,21 +69,12 @@ $(BUILD_FOLDER)/%.o: src/%.s
echo "$(<D)"
mkdir -p "$(@D)"
mkdir -p "$(@D)"
ifeq ($(DEBUG),'0')
${ASM_COMPILER} ${ASM_FLAGS} "$<" -o "$@"
else
${ASM_COMPILER} ${ASM_DEBUG_FLAGS} ${ASM_FLAGS} "$<" -o "$@"
endif

$(BUILD_FOLDER)/%.o: src/%.c
echo "$(@D)"
mkdir -p "$(@D)"
ifeq ($(DEBUG),'0')
$(ARCH_PREFIX)-gcc ${CFLAGS} -c "$<" -o "$@"
else
@echo "Compiling with DEBUG flag"
$(ARCH_PREFIX)-gcc ${CFLAGS} ${C_DEBUG_FLAGS} -c "$<" -o "$@"
endif
$(X_CC) ${CFLAGS} -c "$<" -o "$@"

$(BUILD_FOLDER)/%.o: fonts/%.psf
echo "PSF: $(@D)"
Expand All @@ -78,18 +84,18 @@ $(BUILD_FOLDER)/%.o: fonts/%.psf
$(BUILD_FOLDER)/kernel.bin: $(OBJ_ASM_FILE) $(OBJ_C_FILE) $(OBJ_FONT_FILE) src/linker.ld
echo $(OBJ_ASM_FILE)
echo $(OBJ_FONT_FILE)
$(ARCH_PREFIX)-ld -n -o $(BUILD_FOLDER)/kernel.bin -T src/linker.ld $(OBJ_ASM_FILE) $(OBJ_C_FILE) $(OBJ_FONT_FILE) -Map $(BUILD_FOLDER)/kernel.map
$(X_LD) -n -o $(BUILD_FOLDER)/kernel.bin -T src/linker.ld $(OBJ_ASM_FILE) $(OBJ_C_FILE) $(OBJ_FONT_FILE) -Map $(BUILD_FOLDER)/kernel.map

gdb: DEBUG=1
gdb: $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME)
$(QEMU_SYSTEM) -cdrom $(BUILD_FOLDER)/$(ISO_IMAGE_FILENAME) -monitor unix:qemu-monitor-socket,server,nowait -serial file:dreamos64.log -m 1G -d int -no-reboot -no-shutdown -s -S

tests:
gcc ${TESTFLAGS} tests/test_mem.c tests/test_common.c src/kernel/mem/bitmap.c src/kernel/mem/vmm_util.c src/kernel/mem/pmm.c src/kernel/mem/mmap.c -o tests/test_mem.o
gcc ${TESTFLAGS} tests/test_number_conversion.c tests/test_common.c src/base/numbers.c -o tests/test_number_conversion.o
gcc ${TESTFLAGS} tests/test_kheap.c tests/test_common.c src/kernel/mem/kheap.c src/kernel/mem/bitmap.c src/kernel/mem/pmm.c src/kernel/mem/mmap.c src/kernel/mem/vmm_util.c -o tests/test_kheap.o
gcc ${TESTFLAGS} tests/test_vm.c tests/test_common.c src/kernel/arch/x86_64/system/vm.c src/kernel/mem/vmm_util.c -o tests/test_vm.o
gcc ${TESTFLAGS} tests/test_vfs.c tests/test_common.c src/fs/vfs.c src/drivers/fs/ustar.c -o tests/test_vfs.o
gcc ${TESTFLAGS} tests/test_utils.c src/kernel/mem/vmm_util.c -o tests/test_utils.o
$(X_CC) ${TESTFLAGS} tests/test_mem.c tests/test_common.c src/kernel/mem/bitmap.c src/kernel/mem/vmm_util.c src/kernel/mem/pmm.c src/kernel/mem/mmap.c -o tests/test_mem.o
$(X_CC) ${TESTFLAGS} tests/test_number_conversion.c tests/test_common.c src/base/numbers.c -o tests/test_number_conversion.o
$(X_CC) ${TESTFLAGS} tests/test_kheap.c tests/test_common.c src/kernel/mem/kheap.c src/kernel/mem/bitmap.c src/kernel/mem/pmm.c src/kernel/mem/mmap.c src/kernel/mem/vmm_util.c -o tests/test_kheap.o
$(X_CC) ${TESTFLAGS} tests/test_vm.c tests/test_common.c src/kernel/arch/x86_64/system/vm.c src/kernel/mem/vmm_util.c -o tests/test_vm.o
$(X_CC) ${TESTFLAGS} tests/test_vfs.c tests/test_common.c src/fs/vfs.c src/drivers/fs/ustar.c -o tests/test_vfs.o
$(X_CC) ${TESTFLAGS} tests/test_utils.c src/kernel/mem/vmm_util.c -o tests/test_utils.o
./tests/test_mem.o && ./tests/test_kheap.o && ./tests/test_number_conversion.o && ./tests/test_vm.o && ./tests/test_vfs.o && ./tests/test_utils.o

80 changes: 10 additions & 70 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ But at kernel level several things have been implemented:

* Long mode
* Kernel load in higher half
* Basic i/o functions (using the VGA bios)
* Basic I/O functions (using the VGA bios)
* Basic framebuffer support (it can print strings on the screen, but only on the first half of the screen, the second half will cause a #PF for now)
* IDT Support
* It can load the kernel using 4kb pages or 2Mb pages
Expand All @@ -37,6 +37,7 @@ But at kernel level several things have been implemented:
* It prints the Epoch time! :)
* Extremely basic multi-task/multi-thread support
* Thread switching, thread_sleep and basic spinlock implementation
* Basic Virtual Memory implementation

## Prerequisites:

Expand All @@ -51,80 +52,17 @@ These are the packages you need to build and run it:
* Gcc cross compiler

## Build
### Building the cross compiler

These instructions needs to be completed only the first time (if you already have a x86_64 cross-compiler already configured you probably can skip them, but you need to update the Makefile with your cross-compiler prefix)
To build the cross compiler you need the following packages:
To build dreamos, you need either `gcc` compiled to support the target architecture (in our case `x86-64`) or `clang` toolchain installed, a complete guide on how to build the `gcc` cross-compiler, can be found [here](https://github.com/dreamos82/Osdev-Notes/blob/master/99_Appendices/E_Cross_Compilers.md), for DreamOS the target architecture will be `x86-64`.

* build-essential (on debian derivatives)
* bison
* flex
* libgmp3-dev
* libmpc-dev
* libmpfr-dev
* texinfo
* libcloog

Then you need to download sources of:
* Binutils - available here: https://www.gnu.org/software/binutils/
* Gcc - Available here: https://www.gnu.org/software/gcc/

Decide where to install the tools and declare the environment variables:

```bash
export PREFIX="$HOME/opt/cross"
export TARGET=x86_64-elf
export PATH="$PREFIX/bin:$PATH"
```

The three exports above should be copied in your ~/.bashrc file as convenience (otherwise you need always to invoke them using their full path)
Now create a new folder and enter into it:

```bash
mkdir build-binutils
cd build-binutils
```

Let's assume that this folder is in the same level of the binutils sources.

Then you can compile the tools using the custom PREFIX and TARGET:

```bash
../binutils-x.y.z/configure --target=$TARGET --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror
make
make install
```

* --disable-nls disable national language support, it helps to reduce compile time.
* --with-sysroot Tells binutils to enable sysroot support in the cross-compiler by pointing it to a default empty directory.

If everything goes ok, you can see in your $PREFIX folder the output of the build.
Now is time for gcc, we will use a similar approach. First create a build dir:
```bash
mkdir build-gcc
cd build-gcc
```

Again i assume that it is on the same level of the gcc sources folder.
To compile:

```bash
../gcc-x.y.z/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers
make all-gcc
make all-target-libgcc
make install-gcc
make install-target-libgcc
```

* --enable-languages=c,c++ we tell gcc to enable only those languages
* --without-headers We tell to ignore all the C libraries present for the target.

Now if you want you can make permanent the $PATH update:
For `clang` having the toolchain installed should be enough.

### Build the OS

Before building the os you need to copy a PsfV2 font in the fonts folder, called default.ps (even if building with framebuffer off)
To build just run:
Before building the os you need to copy a PsfV2 font in the fonts folder, called default.ps (even if building with framebuffer off).
A complete guide on how to build _DreamOS 64_ and the parameters availables in the docs folder: [docs/Building.md](docs/Building.md).

Once all the parameters in `build/Config.mk` are set, to build just run:

```bash
make
Expand All @@ -147,9 +85,11 @@ If you use instead:
It will output logging information on a logfile.

Finally:

```bash
make gdb
```

Will compile the OS with debug symbol, and launch qemu with remote debugging enabled (it will wait connection from gdb to start).

There are couple of flags that you can set on the Makefile in order to configure some features:
Expand Down
8 changes: 3 additions & 5 deletions build/Common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ DEF_FLAGS := -D USE_FRAMEBUFFER=$(USE_FRAMEBUFFER) -D SMALL_PAGES=$(SMALL_PAGES

CFLAGS := -std=gnu99 \
-ffreestanding \
-O2 \
-O0 \
-Wall \
-Wextra \
-I src/include \
Expand All @@ -18,7 +18,8 @@ CFLAGS := -std=gnu99 \
-I src/include/sys \
-mno-red-zone \
-mno-sse \
-mcmodel=large
-mcmodel=large \
-fno-stack-protector

CFLAGS += $(DEF_FLAGS)

Expand All @@ -35,8 +36,5 @@ TESTFLAGS := -std=gnu99 \
-DSMALL_PAGES=$(SMALL_PAGES) \
-D_TEST_=1

C_DEBUG_FLAGS := -g \
-DDEBUG=1

PRJ_FOLDERS := src
TEST_FOLDER := tests
1 change: 1 addition & 0 deletions build/Config.mk
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ SMALL_PAGES := 0

# Build Configuration

TOOLCHAIN := clang
BUILD_FOLDER := dist
FONT_FOLDER := fonts

Expand Down
4 changes: 4 additions & 0 deletions docs/Building.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Build configuration

DreamOS can be built using either `gcc` or `clang` toolchain.

This is controlled by the `TOOLCHAIN` variable, inside the Config.mk file, the accepted values are: `gcc` or `clang`.

## Compilation

The following flags have to be properly set before building the os:
Expand Down
4 changes: 3 additions & 1 deletion src/drivers/fs/ustar.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <logging.h>
#include <string.h>

int ustar_open(char *path, int flags) {
int ustar_open(const char *path, int flags, ...) {
loglinef(Verbose, "(ustar_open) called with path: %s and flags: %d", path, flags);
return 3;
}
Expand All @@ -13,6 +13,8 @@ int ustar_close(int ustar_fildes) {
}

ssize_t ustar_read(int ustar_fildes, char *buf, size_t nbytes) {
(void)ustar_fildes;
(void)nbytes;
strcpy(buf, "Test string");
return 12;
}
4 changes: 2 additions & 2 deletions src/fs/vfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ void vfs_init() {
mountpoints[3].file_operations.read = ustar_read;
}

int get_mountpoint_id(char *path) {
int last = 0;
int get_mountpoint_id(const char *path) {
size_t last = 0;
int lastlen = 0;
if (strlen(path) == 0) {
return last;
Expand Down
2 changes: 1 addition & 1 deletion src/include/drivers/fs/ustar.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct ustar_item {
};

typedef struct ustar_item ustar_item;
int ustar_open(char *path, int flags);
int ustar_open(const char *path, int flags, ...);
int ustar_close(int fildes);
ssize_t ustar_read(int fildes, char *buf, size_t nbytes);
#endif
2 changes: 1 addition & 1 deletion src/include/fs/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ extern vfs_file_descriptor_t vfs_opened_files[OPENEDFILES_MAX];
extern unsigned int vfs_fd_index;

void vfs_init();
int get_mountpoint_id(char *path);
int get_mountpoint_id(const char *path);
int mount_fs(char *mountpoint, char* name, fs_file_operations_t file_operations);
char *get_relative_path (char *root_prefix, char *absolute_path);
#endif
2 changes: 1 addition & 1 deletion src/include/kernel/framebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ void set_fb_data(struct multiboot_tag_framebuffer *);
void _fb_printStrAndNumber(const char*, uint64_t, size_t, size_t, uint32_t, uint32_t);

void get_framebuffer_mode(uint32_t* pixels_w, uint32_t* pixels_h, uint32_t* chars_w, uint32_t* chars_h);
void draw_logo();
void draw_logo(uint32_t start_x, uint32_t start_y);
#endif
2 changes: 1 addition & 1 deletion src/include/kernel/mem/mmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ extern const char *mmap_types[];

void _mmap_parse(struct multiboot_tag_mmap*);
void _mmap_setup();
void* _mmap_determine_bitmap_region(uint64_t lower_limit, size_t size);
uintptr_t _mmap_determine_bitmap_region(uint64_t lower_limit, size_t size);
#endif
1 change: 1 addition & 0 deletions src/include/kernel/scheduling/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ bool add_thread_to_task( task_t* task, thread_t* thread );
bool delete_thread_from_task( size_t thread_id, task_t *task );
void prepare_virtual_memory_environment( task_t* task );
void print_thread_list( size_t task_id );
bool remove_thread_from_task(size_t thread_id, task_t *task);

#endif
6 changes: 3 additions & 3 deletions src/include/kernel/scheduling/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ void thread_sleep(size_t millis);
void thread_wakeup(thread_t* thread);
char *get_thread_status(thread_t *thread);
// Functions below are for tests purposes
void noop(char *c);
void noop2(char *c);
void noop3(char *c);
void noop(void *c);
void noop2(void *c);
void noop3(void *c);

#endif
4 changes: 2 additions & 2 deletions src/kernel/arch/x86_64/cpu/ioapic.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ uint32_t read_io_apic_register(uint8_t offset){
}

int read_io_apic_redirect(uint8_t index, io_apic_redirect_entry_t *redtbl_entry){
if (index < 0x10 && index > 0x3F) {
if (index < 0x10 || index > 0x3F) {
return -1;
}
if ((index%2) != 0) {
Expand All @@ -96,7 +96,7 @@ int read_io_apic_redirect(uint8_t index, io_apic_redirect_entry_t *redtbl_entry)
}

int write_io_apic_redirect(uint8_t index, io_apic_redirect_entry_t redtbl_entry) {
if (index < 0x10 && index > 0x3F) {
if (index < 0x10 || index > 0x3F) {
return -1;
}
if ((index%2) != 0) {
Expand Down
2 changes: 0 additions & 2 deletions src/kernel/arch/x86_64/cpu/madt.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,8 @@ void print_madt_table(MADT* table) {
//logline(Verbose, "Printing madt table: ");
uint32_t total_length = 0;
MADT_Item* item = (MADT_Item *) (madt_base);
int counter = 0;
while(total_length + sizeof(MADT) < table->header.Length) {
//loglinef(Verbose, " %d: Type: 0x%x - Length: 0x%x\n", counter, item->type, item->length, item, total_length, ((uint64_t)madt_base + (uint64_t) total_length));
counter++;
total_length = total_length + item->length;
item = (MADT_Item *)((uint64_t)madt_base + (uint64_t) total_length);
}
Expand Down
3 changes: 0 additions & 3 deletions src/kernel/framebuffer/framebuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ void map_framebuffer(struct framebuffer_info fbdata) {
uint32_t pt = PT_ENTRY(_FRAMEBUFFER_MEM_START);
#endif

uint32_t counter = 0;

if(p4_table[pml4] == 0x00l || p3_table_hh[pdpr] == 0x00l){
loglinef(Verbose, "PANIC - PML4 or PDPR Empty - not supported for now\n");
Expand All @@ -66,7 +65,6 @@ void map_framebuffer(struct framebuffer_info fbdata) {
}
for(int j=0; j < VM_PAGES_PER_TABLE && fb_entries > 0; j++){
if(newly_allocated == false){
counter++;
} else {
current_page_table[j] = phys_address + (((VM_PAGES_PER_TABLE * i) + j) * PAGE_SIZE_IN_BYTES) | PAGE_ENTRY_FLAGS;
}
Expand All @@ -81,7 +79,6 @@ void map_framebuffer(struct framebuffer_info fbdata) {
fb_entries++;
}
for(int j=0; fb_entries > 0; j++){
counter++;
fb_entries--;
if((p2_table[pd+j] < phys_address
|| p2_table[pd+j] > (phys_address + fbdata.memory_size))
Expand Down
2 changes: 1 addition & 1 deletion src/kernel/mem/bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void _initialize_bitmap ( unsigned long end_of_reserved_area ) {
if(memory_map_phys_addr > end_of_mapped_physical_memory) {
loglinef(Verbose, "(%s): The address 0x%x is above the initally mapped memory: 0x%x", __FUNCTION__, memory_map_phys_addr, end_of_mapped_physical_memory);
//TODO: This need to be fixed map_phys_to_virt_addr can't be used here since it relies on the bitmap, and it is not initialized yet.
map_phys_to_virt_addr(ALIGN_PHYSADDRESS(memory_map_phys_addr), (memory_map_phys_addr + _HIGHER_HALF_KERNEL_MEM_START), VMM_FLAGS_PRESENT | VMM_FLAGS_WRITE_ENABLE);
map_phys_to_virt_addr((void*)ALIGN_PHYSADDRESS(memory_map_phys_addr), (void*)(memory_map_phys_addr + _HIGHER_HALF_KERNEL_MEM_START), VMM_FLAGS_PRESENT | VMM_FLAGS_WRITE_ENABLE);
} else {
loglinef(Verbose, "(%s): The address 0x%x is not above the initially mapped memory: 0x%x", __FUNCTION__, memory_map_phys_addr, end_of_mapped_physical_memory);
}
Expand Down
Loading

0 comments on commit 058c469

Please sign in to comment.