lab-sched
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "funcs.h" | |
#define COUNTLEN 40 | |
#define TICKS (1ULL << 15) | |
#define DELAY(x) (TICKS << (x)) | |
void contador(unsigned char linea, char color, unsigned char delay) { | |
char counter[COUNTLEN] = {'0'}; // Our ASCII digit counter (RTL). | |
while (1) { | |
char *buf = (void *) 0xb8000 + linea * 160; | |
char *c = &counter[COUNTLEN]; | |
unsigned p = 0; | |
unsigned long long i = 0; | |
while (i++ < DELAY(delay)) | |
; | |
while (counter[p] == '9') { | |
counter[p++] = '0'; | |
} | |
if (!counter[p]++) { | |
counter[p] = '1'; | |
} | |
while (c-- > counter) { | |
*buf++ = *c; | |
*buf++ = color; | |
} | |
sched(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define MAGIC 0x1BADB002 | |
#define FLAGS 0 | |
#define CRC ( -(MAGIC + FLAGS) ) | |
.text | |
.globl _start | |
.align 4 | |
constantes_multiboot: | |
.long MAGIC | |
.long FLAGS | |
.long CRC | |
_start: | |
movl $0, %ebp | |
movl $(bootstacktop), %esp | |
jmp main | |
l: | |
hlt | |
jmp l | |
.data | |
.globl bootstack | |
.globl bootstacktop | |
.align 4096 | |
bootstack: | |
.space 4096 | |
bootstacktop: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef FUNCS_H | |
#define FUNCS_H | |
// Asigna a main() el índice 0, y lo marca como RUNNING. main() | |
// se convierte después en la “idle task” del sistema. | |
void task_init(void); | |
// Crea una nueva tarea, marcándola como READY. No se ejecutará hasta que se | |
// llame a sched(). | |
void task_spawn(void (*entry)(void)); | |
// Finaliza la tarea actual; no volverá a ejecutarse. | |
void task_exit(void); | |
// Planificador round-robin. | |
void sched(void); | |
// Imprime en una línea VGA un contador que se auto-incrementa. Para marcar su | |
// velocidad, hace (TICKS << delay) iteraciones por incremento. En cada TICKS, | |
// llama al planificador. | |
void contador(unsigned char linea, char color, unsigned char delay); | |
// Utilidades. | |
void *stack_alloc(int size); | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "funcs.h" | |
static void contador1(void) { contador(0, 0x2f, 1); } // Verde, rápido. | |
static void contador2(void) { contador(3, 0x6f, 5); } // Naranja, lento. | |
static void contador3(void) { contador(7, 0x4f, 7); } // Rojo, muy lento. | |
int main(void) { | |
task_init(); | |
// Con esta línea, no habría concurrencia. Solo se ejecutaría | |
// el primer contador. | |
// contador1(); | |
task_spawn(contador1); | |
task_spawn(contador2); | |
task_spawn(contador3); | |
while (1) { | |
sched(); // Become the idle task. | |
} | |
} | |
void *stack_alloc(int size) { | |
static void *next = (void *) (8 << 20); // 8 MiB, arbitrariamente. | |
void *ret = next; | |
next -= size; | |
return ret; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
QEMU := qemu-system-i386 -serial mon:stdio -d guest_errors | |
CFLAGS := -std=c99 -m32 -O1 -ggdb3 -gdwarf-4 -Wall -fasm -nostdinc | |
CFLAGS += -fno-pic -fno-inline -fno-omit-frame-pointer -ffreestanding | |
ASFLAGS := $(CFLAGS) | |
SOURCES := $(wildcard *.c) | |
OBJECTS := $(SOURCES:%.c=%.o) | |
kernel: entry.o swtch.o $(OBJECTS) | |
ld -m elf_i386 -Ttext 0x100000 -o $@ $^ | |
objdump -S $@ >$@.asm | |
# Verificar que realmente hemos producido una imagen Multiboot v1. | |
grub-file --is-x86-multiboot $@ | |
qemu: kernel | |
$(QEMU) -kernel $< | |
qemu-gdb: kernel | |
$(QEMU) -kernel $< -nographic -S -gdb tcp:127.0.0.1:7508 | |
gdb: | |
gdb -q -s kernel -ex 'target remote 127.0.0.1:7508' -n -x .gdbinit | |
clean: | |
rm -f kernel kernel.asm *.o core | |
.PHONY: clean qemu qemu-gdb gdb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Context switch | |
// | |
// void swtch(unsigned **oldsp, unsigned **newsp); | |
.globl swtch | |
swtch: | |
ret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "task.h" | |
#include "funcs.h" | |
#define MAX_TASK 128 | |
#define STACK_SIZE 4096 | |
static struct Task *current; | |
static struct Task Tasks[MAX_TASK]; | |
extern void swtch(unsigned **oldsp, unsigned **newsp); | |
void task_init() { | |
current = &Tasks[0]; | |
current->status = RUNNING; | |
} | |
void task_spawn(void (*entry)(void)) { | |
unsigned i = 0; | |
// Encontrar la siguiente posición libre. | |
while (i < MAX_TASK && Tasks[i].status != FREE) | |
i++; | |
void *stack = stack_alloc(STACK_SIZE) - sizeof(struct TaskData); | |
Tasks[i].stack = stack; | |
Tasks[i].status = READY; | |
// Preparar el stack conforme a lo que espera swtch(). | |
struct TaskData *d = stack; | |
*d = (const struct TaskData){}; // Inicializa a 0. | |
d->entry_fn = (unsigned) entry; | |
} | |
void sched() { | |
struct Task *new = 0; | |
struct Task *old = current; | |
for (int i = 0; i < MAX_TASK; i++) { | |
if (Tasks[i].status == READY) | |
new = &Tasks[i]; | |
} | |
if (new) { | |
old->status = READY; // XXX 🤔? | |
current = new; | |
current->status = RUNNING; | |
swtch(&old->stack, ¤t->stack); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef TASK_H | |
#define TASK_H | |
enum TaskStatus { | |
FREE = 0, | |
READY, | |
RUNNING, | |
}; | |
struct Task { | |
unsigned *stack; | |
enum TaskStatus status; | |
}; | |
struct TaskData { | |
// Registers as pushed by pusha. | |
unsigned reg_edi; | |
unsigned reg_esi; | |
unsigned __unused_ebp; | |
unsigned __unused_esp; | |
unsigned reg_ebx; | |
unsigned reg_edx; | |
unsigned reg_ecx; | |
unsigned reg_eax; | |
// Saved eflags. | |
unsigned reg_eflags; | |
// Saved %ebp; makes swtch’s code simpler. | |
unsigned reg_ebp; | |
// Return address used in swtch’s "ret". | |
unsigned entry_fn; | |
} __attribute__((packed)); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment