Starting Point
This commit is contained in:
1
arch/bsp/.gitignore
vendored
Normal file
1
arch/bsp/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# empty gitignore
|
||||||
42
arch/bsp/yellow_led.c
Normal file
42
arch/bsp/yellow_led.c
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#include <arch/bsp/yellow_led.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
static constexpr unsigned int GPIO_BASE = 0x7E200000 - 0x3F000000;
|
||||||
|
static constexpr unsigned int YELLOW_LED = 7u;
|
||||||
|
static constexpr unsigned int GPF_BITS = 3u;
|
||||||
|
static constexpr unsigned int GPF_MASK = 0b111u;
|
||||||
|
static constexpr unsigned int YELLOW_LED_GPF_SHIFT = YELLOW_LED * GPF_BITS;
|
||||||
|
|
||||||
|
enum gpio_func {
|
||||||
|
gpio_input = 0x0,
|
||||||
|
gpio_output = 0x1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct gpio {
|
||||||
|
unsigned int func[6];
|
||||||
|
unsigned int unused0;
|
||||||
|
unsigned int set[2];
|
||||||
|
unsigned int unused1;
|
||||||
|
unsigned int clr[2];
|
||||||
|
};
|
||||||
|
static_assert(offsetof(struct gpio, func) == 0x00);
|
||||||
|
static_assert(offsetof(struct gpio, set) == 0x1C);
|
||||||
|
static_assert(offsetof(struct gpio, clr) == 0x28);
|
||||||
|
|
||||||
|
static volatile struct gpio *const gpio_port = (struct gpio *)GPIO_BASE;
|
||||||
|
|
||||||
|
void init_yellow(void)
|
||||||
|
{
|
||||||
|
gpio_port->func[0] = (gpio_port->func[0] & ~(GPF_MASK << YELLOW_LED_GPF_SHIFT)) |
|
||||||
|
(gpio_output << YELLOW_LED_GPF_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void yellow_on(void)
|
||||||
|
{
|
||||||
|
gpio_port->set[0] = 1 << YELLOW_LED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void yellow_off(void)
|
||||||
|
{
|
||||||
|
gpio_port->clr[0] = 1 << YELLOW_LED;
|
||||||
|
}
|
||||||
1
arch/cpu/.gitignore
vendored
Normal file
1
arch/cpu/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# empty gitignore
|
||||||
70
arch/cpu/entry.S
Normal file
70
arch/cpu/entry.S
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
|
||||||
|
.section .init
|
||||||
|
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
/* Erkennen ob Hypervisor Mode aktiv */
|
||||||
|
mrs r0, cpsr
|
||||||
|
and r0, r0, #0x1F
|
||||||
|
mov r1, #0x1A //Modebits = 0x1A = Hypervisor Mode
|
||||||
|
cmp r0, r1 //Vergleichen und Statusbits setzen für bedingte Sprünge
|
||||||
|
|
||||||
|
/* Wenn Hypemode erkannt: abschalten (sprung nach _exitHyper)
|
||||||
|
* wenn nicht erkannt: dann weitermachen (weiterlaufen nach _bsprak)
|
||||||
|
*/
|
||||||
|
beq _exitHyper
|
||||||
|
|
||||||
|
/* Qemu startet immer alle 4 Kerne
|
||||||
|
* Wir lassen alle anderen Kerne endless loopen
|
||||||
|
*/
|
||||||
|
_checkCores:
|
||||||
|
/* Id des Cpu Cores Abfragen */
|
||||||
|
mrc p15, 0, r0, c0, c0, 5
|
||||||
|
/* Falls nicht core 0 Core disablen */
|
||||||
|
tst r0, #3
|
||||||
|
bne _parkCore
|
||||||
|
|
||||||
|
/* not modeled in qemu 6.0 */
|
||||||
|
_enableAlignCheck:
|
||||||
|
/* SCTLR des cp15 laden */
|
||||||
|
mrc p15, 0, r0, c1, c0, 0
|
||||||
|
/* A-bit (c1[1]) auf 1 setzen */
|
||||||
|
orr r0, r0, #0x2
|
||||||
|
/* neues SCTLR speichern */
|
||||||
|
mcr p15, 0, r0, c1, c0, 0
|
||||||
|
|
||||||
|
|
||||||
|
_bsprak:
|
||||||
|
/* Validen Stack Pointer setzten */
|
||||||
|
ldr sp,=0x100000
|
||||||
|
/* Zu c Code springen */
|
||||||
|
bl start_kernel
|
||||||
|
.Lend:
|
||||||
|
WFI
|
||||||
|
b .Lend
|
||||||
|
|
||||||
|
_parkCore:
|
||||||
|
/* Interrupts für Core 1 bis 3 ausschalten */
|
||||||
|
cpsid if
|
||||||
|
/* In Endlosschleife springen */
|
||||||
|
b .Lend
|
||||||
|
|
||||||
|
_exitHyper:
|
||||||
|
|
||||||
|
/* Rücksprungadresse ins Hypervisor Rücksprungregister schreiben.
|
||||||
|
* Dies ist das Label _bsprak für die normale Programmausfürung.
|
||||||
|
*/
|
||||||
|
ldr lr, =_checkCores
|
||||||
|
msr ELR_hyp, lr
|
||||||
|
|
||||||
|
/* Der Hypervisor mode ist auch "nur" eine etwas kompliziertere Exception.
|
||||||
|
* Also springen wir aus dieser zurück.
|
||||||
|
* (Rücksprunge in Aufgabe 2 sind anders zu lösen!).
|
||||||
|
* Dazu zunächst das CPSR auslesen und die Modebits zum Supervisor ändern.
|
||||||
|
* Danach dies in das SPSR für den Rücksprung schreiben.
|
||||||
|
*/
|
||||||
|
mrs r0, cpsr
|
||||||
|
bic r0, r0, #0x1F
|
||||||
|
orr r0, r0, #0x13 //Supervisormode
|
||||||
|
msr spsr_hyp, r0
|
||||||
|
eret
|
||||||
1
include/arch/bsp/.gitignore
vendored
Normal file
1
include/arch/bsp/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# empty gitignore
|
||||||
8
include/arch/bsp/yellow_led.h
Normal file
8
include/arch/bsp/yellow_led.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef YELLOW_LED_H
|
||||||
|
#define YELLOW_LED_H
|
||||||
|
|
||||||
|
void init_yellow(void);
|
||||||
|
void yellow_on(void);
|
||||||
|
void yellow_off(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
1
include/arch/cpu/.gitignore
vendored
Normal file
1
include/arch/cpu/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# empty gitignore
|
||||||
48
include/config.h
Normal file
48
include/config.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef CONFIG_H_
|
||||||
|
#define CONFIG_H_
|
||||||
|
|
||||||
|
/* Falls auf den Boards gearbeitet wird am besten
|
||||||
|
* die nächste Zeile auskommentieren
|
||||||
|
*/
|
||||||
|
#define BUILD_FOR_QEMU
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file config.h
|
||||||
|
*
|
||||||
|
* Enthält defines und static Funktionen zum testen der
|
||||||
|
* Implementierung. Wir tauschen diese Werte/Funktionen beim
|
||||||
|
* Korrigieren zum Testen aus. Bitte fügt hier KEINE weiteren
|
||||||
|
* defines oÄ ein. Ihr könnt diese Werte zum Testen natürlich
|
||||||
|
* auch gerne selbst verändern.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void test_kernel [[gnu::weak]] (void);
|
||||||
|
void test_user [[gnu::weak]] (void *args);
|
||||||
|
void test_user_main [[gnu::weak]] (void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erst ab Aufgabenblatt 2 relevant
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef BUILD_FOR_QEMU
|
||||||
|
/* Werte zum testen unter QEMU */
|
||||||
|
static constexpr unsigned int BUSY_WAIT_COUNTER = 10000000;
|
||||||
|
#else
|
||||||
|
/* Werte zum testen auf der Hardware */
|
||||||
|
static constexpr unsigned int BUSY_WAIT_COUNTER = 30000;
|
||||||
|
#endif // BUILD_FOR_QEMU
|
||||||
|
|
||||||
|
static constexpr unsigned int PRINT_COUNT = 5;
|
||||||
|
|
||||||
|
// Wir testen nur mit Werten die durch 2^n darstellbar sind
|
||||||
|
static constexpr unsigned int UART_INPUT_BUFFER_SIZE = 128;
|
||||||
|
|
||||||
|
// Timer Interrupt Interval zum testen in Mikrosekunden
|
||||||
|
// Systimer taktet mit 1MHz
|
||||||
|
// 1000000 -> 1 Sekunde
|
||||||
|
static constexpr unsigned int TIMER_INTERVAL = 1000000;
|
||||||
|
|
||||||
|
#endif // __ASSEMBLER__
|
||||||
|
#endif // CONFIG_H_
|
||||||
1
include/kernel/.gitignore
vendored
Normal file
1
include/kernel/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# empty gitignore
|
||||||
1
include/lib/.gitignore
vendored
Normal file
1
include/lib/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# empty gitignore
|
||||||
110
include/lib/list.h
Normal file
110
include/lib/list.h
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#ifndef LIB_LIST_H_
|
||||||
|
#define LIB_LIST_H_
|
||||||
|
/*
|
||||||
|
* \file list.h
|
||||||
|
* \brief Doppelt verkettete List Datenstruktur
|
||||||
|
*
|
||||||
|
* Diese Datei ist eine Hilfestellung für Aufgabe 3.
|
||||||
|
* Sie erspart euch den Aufwand, selber eine doppelt verkettete Liste zu implementieren.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// List Node struct
|
||||||
|
typedef struct list_node {
|
||||||
|
struct list_node *next;
|
||||||
|
struct list_node *prev;
|
||||||
|
} list_node;
|
||||||
|
|
||||||
|
// Makro zum initialisieren einer Liste
|
||||||
|
#define list_create(N) \
|
||||||
|
static list_node head__##N = { &(head__##N), &(head__##N) }; \
|
||||||
|
static list_node *N = &(head__##N)
|
||||||
|
|
||||||
|
//checks if list is empty
|
||||||
|
[[nodiscard]] static inline bool list_is_empty(list_node *head)
|
||||||
|
{
|
||||||
|
return head == head->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gibt das erste Elemnt der Liste zurück
|
||||||
|
[[nodiscard, maybe_unused]] static inline list_node *list_get_first(list_node *head)
|
||||||
|
{
|
||||||
|
if (list_is_empty(head)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return head->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gibt das letzte Element der Liste zurück
|
||||||
|
[[nodiscard, maybe_unused]] static inline list_node *list_get_last(list_node *head)
|
||||||
|
{
|
||||||
|
if (list_is_empty(head)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return head->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Füge Elemente hinzu (Hilfsfunktion)
|
||||||
|
static inline void list_add_(list_node *node, list_node *prev)
|
||||||
|
{
|
||||||
|
node->prev = prev;
|
||||||
|
node->next = prev->next;
|
||||||
|
|
||||||
|
prev->next->prev = node;
|
||||||
|
prev->next = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Füge Element am Anfang der Liste hinzu
|
||||||
|
[[maybe_unused]] static inline void list_add_first(list_node *head, list_node *new)
|
||||||
|
{
|
||||||
|
list_add_(new, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Füge Element am Ende der Liste hinzu
|
||||||
|
[[maybe_unused]] static inline void list_add_last(list_node *head, list_node *new)
|
||||||
|
{
|
||||||
|
list_add_(new, head->prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entferne Element (Hilfsfunktion)
|
||||||
|
static inline void list_remove_(list_node *node)
|
||||||
|
{
|
||||||
|
node->prev->next = node->next;
|
||||||
|
node->next->prev = node->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entfernt das erste Element aus der Liste und gibt es zurück
|
||||||
|
[[maybe_unused]] static inline list_node *list_remove_first(list_node *head)
|
||||||
|
{
|
||||||
|
if (list_is_empty(head)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
list_node *del = head->next;
|
||||||
|
list_remove_(del);
|
||||||
|
return del;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entferne das letzte Element aus der Liste und gibt es zurück
|
||||||
|
[[maybe_unused]] static inline list_node *list_remove_last(list_node *head)
|
||||||
|
{
|
||||||
|
if (list_is_empty(head)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
list_node *del = head->prev;
|
||||||
|
list_remove_(del);
|
||||||
|
return del;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entfernt das spezielle Element aus der Liste
|
||||||
|
[[maybe_unused]] static inline list_node *list_remove(list_node *head, list_node *rem)
|
||||||
|
{
|
||||||
|
list_node *curr;
|
||||||
|
for (curr = head->next; curr != head; curr = curr->next) {
|
||||||
|
if (curr == rem) {
|
||||||
|
list_remove_(curr);
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // LIB_LIST_H_
|
||||||
89
include/lib/ringbuffer.h
Normal file
89
include/lib/ringbuffer.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#ifndef RINGBUFFER_H_
|
||||||
|
#define RINGBUFFER_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Ringbuffer Datenstruktur
|
||||||
|
* \file ringbuffer.h
|
||||||
|
*
|
||||||
|
* Diese Datei ist eine Hilfestellung für Aufgabe 2.
|
||||||
|
* Sie erspart euch den Aufwand, selber einen Ringbuffer zu implementieren.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ring_buff {
|
||||||
|
unsigned int head;
|
||||||
|
unsigned int tail;
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int mask;
|
||||||
|
char *buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Überprüft ob eine positive Zahl eine Zweierpotenz ist
|
||||||
|
*
|
||||||
|
* Beispiel: (0b100 & 0b011) == 0b000.
|
||||||
|
*/
|
||||||
|
#define is_power_of_two(val) (((val) & ((val) - 1)) == 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Macro um einen Ringbuffer zu erstellen
|
||||||
|
* \param name Bezeichnung des Buffers
|
||||||
|
* \param size Größe des Buffers
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define create_ringbuffer(name, size) \
|
||||||
|
static_assert((size) >= 1, "Size of Ringbuffer has to be at least 1"); \
|
||||||
|
static_assert(is_power_of_two(size), "Size of Ringbuffer has to be a power of 2"); \
|
||||||
|
static char _b_##name[size]; \
|
||||||
|
static struct ring_buff _##name = { 0, 0, (size), (size) - 1, _b_##name }; \
|
||||||
|
static volatile struct ring_buff *name = &_##name
|
||||||
|
|
||||||
|
[[nodiscard]] static bool buff_is_empty(volatile struct ring_buff *b)
|
||||||
|
{
|
||||||
|
return b->head == b->tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static bool buff_is_full(volatile struct ring_buff *b)
|
||||||
|
{
|
||||||
|
return ((b->tail & b->mask) == (b->head & b->mask)) && !buff_is_empty(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool buff_putc(volatile struct ring_buff *b, char c)
|
||||||
|
{
|
||||||
|
if (buff_is_full(b)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
b->buffer[b->head & b->mask] = c;
|
||||||
|
b->head++;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char buff_getc(volatile struct ring_buff *b)
|
||||||
|
{
|
||||||
|
while (buff_is_empty(b)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
char c = b->buffer[b->tail & b->mask];
|
||||||
|
b->tail++;
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard, maybe_unused]] static char buff_peekc(volatile struct ring_buff *b)
|
||||||
|
{
|
||||||
|
while (buff_is_empty(b)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return b->buffer[b->tail & b->mask];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard, maybe_unused]] static char buff_peekc_last(volatile struct ring_buff *b)
|
||||||
|
{
|
||||||
|
while (buff_is_empty(b)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return b->buffer[(b->head - 1) & b->mask];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
5
include/user/main.h
Normal file
5
include/user/main.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#ifndef MAIN_H
|
||||||
|
#define MAIN_H
|
||||||
|
|
||||||
|
void main(void *args);
|
||||||
|
#endif
|
||||||
11
kernel.lds
Normal file
11
kernel.lds
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x00008000;
|
||||||
|
.init : { *(.init) }
|
||||||
|
.text : { *(.text) }
|
||||||
|
.rodata : { *(.rodata) }
|
||||||
|
. = ALIGN(1<<20);
|
||||||
|
.data : { *(.data) }
|
||||||
|
.bss : { *(.bss) }
|
||||||
|
}
|
||||||
1
kernel/.gitignore
vendored
Normal file
1
kernel/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# empty gitignore
|
||||||
20
kernel/start.c
Normal file
20
kernel/start.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include <arch/bsp/yellow_led.h>
|
||||||
|
|
||||||
|
static volatile unsigned int counter = 0;
|
||||||
|
|
||||||
|
static void increment_counter(void)
|
||||||
|
{
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_kernel [[noreturn]] (void);
|
||||||
|
void start_kernel [[noreturn]] (void)
|
||||||
|
{
|
||||||
|
init_yellow();
|
||||||
|
yellow_on();
|
||||||
|
|
||||||
|
// Endless counter
|
||||||
|
while (true) {
|
||||||
|
increment_counter();
|
||||||
|
}
|
||||||
|
}
|
||||||
1
lib/.gitignore
vendored
Normal file
1
lib/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# empty gitignore
|
||||||
59
lib/mem.c
Normal file
59
lib/mem.c
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int memcmp(const void *s1, const void *s2, size_t n)
|
||||||
|
{
|
||||||
|
const unsigned char *str1 = s1;
|
||||||
|
const unsigned char *str2 = s2;
|
||||||
|
int res = 0;
|
||||||
|
while (n > 0 && res == 0) {
|
||||||
|
res = *str1 - *str2;
|
||||||
|
str1++;
|
||||||
|
str2++;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memcpy(void *restrict s1, const void *restrict s2, size_t n)
|
||||||
|
{
|
||||||
|
char *restrict str1 = s1;
|
||||||
|
const char *restrict str2 = s2;
|
||||||
|
while (n > 0) {
|
||||||
|
*str1 = *str2;
|
||||||
|
str1++;
|
||||||
|
str2++;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
return s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memmove(void *s1, const void *s2, size_t n)
|
||||||
|
{
|
||||||
|
char *str1 = s1;
|
||||||
|
const char *str2 = s2;
|
||||||
|
if (str1 < str2) {
|
||||||
|
while (n > 0) {
|
||||||
|
*str1 = *str2;
|
||||||
|
str1++;
|
||||||
|
str2++;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (n > 0) {
|
||||||
|
n--;
|
||||||
|
*(str1 + n) = *(str2 + n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memset(void *s, int c, size_t n)
|
||||||
|
{
|
||||||
|
unsigned char *str = s;
|
||||||
|
while (n > 0) {
|
||||||
|
*str = (unsigned char)c;
|
||||||
|
str++;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
154
lib/ubsan.c
Normal file
154
lib/ubsan.c
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <arch/bsp/yellow_led.h>
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#define halt() \
|
||||||
|
do { \
|
||||||
|
asm("cpsid if"); \
|
||||||
|
while (true) { \
|
||||||
|
asm("wfi"); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
void kprintf [[gnu::format(printf, 1, 2)]] (const char *format, ...);
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn"
|
||||||
|
void kprintf [[gnu::weak, gnu::format(printf, 1, 2)]] (const char *, ...)
|
||||||
|
{
|
||||||
|
init_yellow();
|
||||||
|
while (true) {
|
||||||
|
for (volatile unsigned int i = 0; i < BUSY_WAIT_COUNTER; i++) {
|
||||||
|
}
|
||||||
|
yellow_on();
|
||||||
|
for (volatile unsigned int i = 0; i < BUSY_WAIT_COUNTER; i++) {
|
||||||
|
}
|
||||||
|
yellow_off();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
// structs copyed form the linux kernel
|
||||||
|
// https://github.com/torvalds/linux/blob/master/lib/ubsan.h
|
||||||
|
|
||||||
|
struct source_location {
|
||||||
|
const char *file_name;
|
||||||
|
const uint32_t line;
|
||||||
|
const uint32_t column;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_descriptor {
|
||||||
|
const uint16_t type_kind;
|
||||||
|
const uint16_t type_info;
|
||||||
|
const char type_name[1];
|
||||||
|
const char unused[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_mismatch_data_v1 {
|
||||||
|
const struct source_location location;
|
||||||
|
const struct type_descriptor *type;
|
||||||
|
const unsigned char log_alignment;
|
||||||
|
const unsigned char type_check_kind;
|
||||||
|
const char unused[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct out_of_bounds_data {
|
||||||
|
struct source_location loc;
|
||||||
|
struct type_descriptor *array_type;
|
||||||
|
struct type_descriptor *index_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(unsigned int) == sizeof(long));
|
||||||
|
|
||||||
|
static void print_source_location(const struct source_location *location)
|
||||||
|
{
|
||||||
|
kprintf("%s:%u:%u", location->file_name, (unsigned int)location->line,
|
||||||
|
(unsigned int)location->column);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEF_UBSAN_HANDLER(name) \
|
||||||
|
void __ubsan_handle_##name [[noreturn]] (const struct source_location *location); \
|
||||||
|
void __ubsan_handle_##name [[noreturn]] (const struct source_location *location) \
|
||||||
|
{ \
|
||||||
|
kprintf("Undefined behavior detected: " #name " at "); \
|
||||||
|
print_source_location(location); \
|
||||||
|
kprintf("\n"); \
|
||||||
|
halt(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF_UBSAN_HANDLER(add_overflow)
|
||||||
|
DEF_UBSAN_HANDLER(add_overflow_abort)
|
||||||
|
DEF_UBSAN_HANDLER(alignment_assumption)
|
||||||
|
DEF_UBSAN_HANDLER(builtin_unreachable)
|
||||||
|
DEF_UBSAN_HANDLER(alignment_assumption_abort)
|
||||||
|
DEF_UBSAN_HANDLER(cfi_check_fail)
|
||||||
|
DEF_UBSAN_HANDLER(cfi_bad_type)
|
||||||
|
DEF_UBSAN_HANDLER(divrem_overflow)
|
||||||
|
DEF_UBSAN_HANDLER(cfi_check_fail_abort)
|
||||||
|
DEF_UBSAN_HANDLER(dynamic_type_cache_miss)
|
||||||
|
DEF_UBSAN_HANDLER(divrem_overflow_abort)
|
||||||
|
DEF_UBSAN_HANDLER(float_cast_overflow)
|
||||||
|
DEF_UBSAN_HANDLER(dynamic_type_cache_miss_abort)
|
||||||
|
DEF_UBSAN_HANDLER(function_type_mismatch_v1)
|
||||||
|
DEF_UBSAN_HANDLER(float_cast_overflow_abort)
|
||||||
|
DEF_UBSAN_HANDLER(implicit_conversion)
|
||||||
|
DEF_UBSAN_HANDLER(function_type_mismatch_v1_abort)
|
||||||
|
DEF_UBSAN_HANDLER(invalid_builtin)
|
||||||
|
DEF_UBSAN_HANDLER(implicit_conversion_abort)
|
||||||
|
DEF_UBSAN_HANDLER(invalid_objc_cast)
|
||||||
|
DEF_UBSAN_HANDLER(invalid_builtin_abort)
|
||||||
|
DEF_UBSAN_HANDLER(load_invalid_value)
|
||||||
|
DEF_UBSAN_HANDLER(invalid_objc_cast_abort)
|
||||||
|
DEF_UBSAN_HANDLER(missing_return)
|
||||||
|
DEF_UBSAN_HANDLER(load_invalid_value_abort)
|
||||||
|
DEF_UBSAN_HANDLER(mul_overflow_abort)
|
||||||
|
DEF_UBSAN_HANDLER(mul_overflow)
|
||||||
|
DEF_UBSAN_HANDLER(negate_overflow_abort)
|
||||||
|
DEF_UBSAN_HANDLER(negate_overflow)
|
||||||
|
DEF_UBSAN_HANDLER(nonnull_arg_abort)
|
||||||
|
DEF_UBSAN_HANDLER(nonnull_arg)
|
||||||
|
DEF_UBSAN_HANDLER(nonnull_return_v1_abort)
|
||||||
|
DEF_UBSAN_HANDLER(nonnull_return_v1)
|
||||||
|
DEF_UBSAN_HANDLER(nullability_arg_abort)
|
||||||
|
DEF_UBSAN_HANDLER(nullability_arg)
|
||||||
|
DEF_UBSAN_HANDLER(nullability_return_v1_abort)
|
||||||
|
DEF_UBSAN_HANDLER(nullability_return_v1)
|
||||||
|
DEF_UBSAN_HANDLER(out_of_bounds_abort)
|
||||||
|
DEF_UBSAN_HANDLER(pointer_overflow_abort)
|
||||||
|
DEF_UBSAN_HANDLER(pointer_overflow)
|
||||||
|
DEF_UBSAN_HANDLER(shift_out_of_bounds_abort)
|
||||||
|
DEF_UBSAN_HANDLER(shift_out_of_bounds)
|
||||||
|
DEF_UBSAN_HANDLER(sub_overflow_abort)
|
||||||
|
DEF_UBSAN_HANDLER(sub_overflow)
|
||||||
|
DEF_UBSAN_HANDLER(type_mismatch_v1_abort)
|
||||||
|
DEF_UBSAN_HANDLER(vla_bound_not_positive_abort)
|
||||||
|
DEF_UBSAN_HANDLER(vla_bound_not_positive)
|
||||||
|
|
||||||
|
void __ubsan_handle_out_of_bounds
|
||||||
|
[[noreturn]] (struct out_of_bounds_data *data, unsigned long index);
|
||||||
|
void __ubsan_handle_out_of_bounds
|
||||||
|
[[noreturn]] (struct out_of_bounds_data *data, unsigned long index)
|
||||||
|
{
|
||||||
|
kprintf("Undefined behavior detected: out of bounds access index %u at ",
|
||||||
|
(unsigned int)index);
|
||||||
|
print_source_location(&data->loc);
|
||||||
|
kprintf("\n");
|
||||||
|
halt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ubsan_handle_type_mismatch_v1 [[noreturn]] (struct type_mismatch_data_v1 *data_v1, int ptr);
|
||||||
|
void __ubsan_handle_type_mismatch_v1 [[noreturn]] (struct type_mismatch_data_v1 *data_v1, int ptr)
|
||||||
|
{
|
||||||
|
if (ptr == (uint32_t)NULL) {
|
||||||
|
kprintf("Undefined behavior detected: null pointer access at ");
|
||||||
|
} else if (data_v1->log_alignment && (ptr & (data_v1->log_alignment - 1))) {
|
||||||
|
kprintf("Undefined behavior detected: unaligned access at ");
|
||||||
|
} else {
|
||||||
|
kprintf("Undefined behavior detected: type mismatch at ");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_source_location(&data_v1->location);
|
||||||
|
kprintf("\n");
|
||||||
|
halt();
|
||||||
|
}
|
||||||
1
user/.gitignore
vendored
Normal file
1
user/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# empty gitignore
|
||||||
6
user/main.c
Normal file
6
user/main.c
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include <user/main.h>
|
||||||
|
#include <config.h>
|
||||||
|
// This is just a placeholder
|
||||||
|
void main(void *)
|
||||||
|
{
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user