[arch][m68k] Merge in Motorola 68k port
This commit is contained in:
1
.github/workflows/github-ci.yml
vendored
1
.github/workflows/github-ci.yml
vendored
@@ -15,6 +15,7 @@ jobs:
|
||||
project:
|
||||
- qemu-virt-arm32-test
|
||||
- qemu-virt-arm64-test
|
||||
- qemu-virt-m68k-test
|
||||
- qemu-microblaze-test
|
||||
- qemu-mips-test
|
||||
- qemu-virt-riscv32-test
|
||||
|
||||
44
arch/m68k/arch.c
Normal file
44
arch/m68k/arch.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/trace.h>
|
||||
#include <lk/debug.h>
|
||||
#include <stdint.h>
|
||||
#include <arch/m68k.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
void arch_early_init(void) {
|
||||
LTRACE;
|
||||
|
||||
// set the exception vector base
|
||||
extern uint32_t exc_vectors[256];
|
||||
asm volatile("movec %0, %%vbr" :: "r"(exc_vectors));
|
||||
}
|
||||
|
||||
void arch_init(void) {
|
||||
LTRACE;
|
||||
}
|
||||
|
||||
void arch_idle(void) {
|
||||
// set the SR such that we're in supervisor state and no ints are masked
|
||||
asm("stop #0x2000" ::: "cc");
|
||||
}
|
||||
|
||||
void arch_chain_load(void *entry, ulong arg0, ulong arg1, ulong arg2, ulong arg3) {
|
||||
PANIC_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
/* unimplemented cache operations */
|
||||
void arch_disable_cache(uint flags) { PANIC_UNIMPLEMENTED; }
|
||||
void arch_enable_cache(uint flags) { PANIC_UNIMPLEMENTED; }
|
||||
|
||||
void arch_clean_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; }
|
||||
void arch_clean_invalidate_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; }
|
||||
void arch_invalidate_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; }
|
||||
void arch_sync_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; }
|
||||
|
||||
29
arch/m68k/asm.S
Normal file
29
arch/m68k/asm.S
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/asm.h>
|
||||
|
||||
// void m68k_context_switch(struct m68k_context_switch_frame *oldcs, struct m68k_context_switch_frame *newcs);
|
||||
FUNCTION(m68k_context_switch)
|
||||
movel %sp@+,%d0 // pop PC off the stack
|
||||
movel %sp@,%a0 // oldcs
|
||||
movel %sp@(4),%a1 // newcs
|
||||
|
||||
// save old state
|
||||
movel %sp, %a0@(0) // oldcs.sp
|
||||
movel %d0, %a0@(4) // oldcs.pc
|
||||
moveml %d2-%d7/%a2-%a6, %a0@(8) // oldcs.<base of callee saved list>
|
||||
|
||||
// load new state
|
||||
movel %a1@(0), %sp // newcs.sp
|
||||
movel %a1@(4), %sp@- // newcs.pc -> stack
|
||||
moveml %a1@(8), %d2-%d7/%a2-%a6 // newcs.<base of callee saved list>
|
||||
|
||||
// return to new PC
|
||||
rts
|
||||
END_FUNCTION(m68k_context_switch)
|
||||
|
||||
37
arch/m68k/exceptions.c
Normal file
37
arch/m68k/exceptions.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <arch/m68k.h>
|
||||
#include <inttypes.h>
|
||||
#include <lk/debug.h>
|
||||
#include <lk/trace.h>
|
||||
#include <kernel/thread.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
// defined in platform interrupt controller
|
||||
extern enum handler_return m68k_platform_irq(uint8_t irq);
|
||||
|
||||
void m68k_exception(void *frame, uint8_t code) {
|
||||
LTRACEF("frame %p, code %hhu\n", frame, code);
|
||||
|
||||
panic("unimplemented exception %hhu\n", code);
|
||||
}
|
||||
|
||||
void m68k_irq(void *frame, uint8_t code) {
|
||||
LTRACEF("frame %p, code %hhu\n", frame, code);
|
||||
|
||||
if (unlikely(code == 0)) {
|
||||
// spurious interrupt
|
||||
return;
|
||||
}
|
||||
|
||||
enum handler_return ret = m68k_platform_irq(code);
|
||||
if (ret == INT_RESCHEDULE) {
|
||||
thread_preempt();
|
||||
}
|
||||
}
|
||||
83
arch/m68k/exceptions_asm.S
Normal file
83
arch/m68k/exceptions_asm.S
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/asm.h>
|
||||
|
||||
.text
|
||||
|
||||
.macro irq_vector n
|
||||
m68k_irq_vector_\n:
|
||||
moveml %d0-%d7/%a0-%a6, %sp@-
|
||||
|
||||
pea \n
|
||||
movel %sp,%sp@-
|
||||
jsr m68k_irq
|
||||
addaw #8, %sp
|
||||
|
||||
moveml %sp@+, %d0-%d7/%a0-%a6
|
||||
rte
|
||||
.endm
|
||||
|
||||
irq_vector 0
|
||||
irq_vector 1
|
||||
irq_vector 2
|
||||
irq_vector 3
|
||||
irq_vector 4
|
||||
irq_vector 5
|
||||
irq_vector 6
|
||||
irq_vector 7
|
||||
|
||||
.macro exception_vector name n
|
||||
\name:
|
||||
moveml %d0-%d7/%a0-%a6, %sp@-
|
||||
|
||||
pea \n
|
||||
movel %sp,%sp@-
|
||||
jsr m68k_exception
|
||||
addaw #8, %sp
|
||||
|
||||
moveml %sp@+, %d0-%d7/%a0-%a6
|
||||
rte
|
||||
.endm
|
||||
|
||||
exception_vector m68k_access_fault 2
|
||||
exception_vector m68k_address_error 3
|
||||
exception_vector m68k_illegal_vector 4
|
||||
exception_vector m68k_div_by_zero 5
|
||||
exception_vector m68k_chk 6
|
||||
exception_vector m68k_trap 7
|
||||
exception_vector m68k_priv_violation 8
|
||||
exception_vector m68k_trace 9
|
||||
exception_vector m68k_unimp_aline 10
|
||||
exception_vector m68k_unimp_fline 11
|
||||
|
||||
.section .text.vectab
|
||||
.align 4
|
||||
DATA(exc_vectors)
|
||||
.org 0x8
|
||||
.long m68k_access_fault
|
||||
.long m68k_address_error
|
||||
.long m68k_illegal_vector
|
||||
.long m68k_div_by_zero
|
||||
.long m68k_chk
|
||||
.long m68k_trap
|
||||
.long m68k_priv_violation
|
||||
.long m68k_trace
|
||||
.long m68k_unimp_aline
|
||||
.long m68k_unimp_fline
|
||||
.org 0x60
|
||||
.long m68k_irq_vector_0
|
||||
.long m68k_irq_vector_1
|
||||
.long m68k_irq_vector_2
|
||||
.long m68k_irq_vector_3
|
||||
.long m68k_irq_vector_4
|
||||
.long m68k_irq_vector_5
|
||||
.long m68k_irq_vector_6
|
||||
.long m68k_irq_vector_7
|
||||
.org 4*256
|
||||
END_DATA(exc_vectors)
|
||||
|
||||
58
arch/m68k/include/arch/arch_ops.h
Normal file
58
arch/m68k/include/arch/arch_ops.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <lk/compiler.h>
|
||||
#include <lk/debug.h>
|
||||
|
||||
__BEGIN_CDECLS
|
||||
|
||||
#define M68K_SR_IPM_MASK ((0b111 << 8)) // interrupt priority mask
|
||||
|
||||
static inline void arch_enable_ints(void) {
|
||||
asm volatile("andi %0, %%sr" :: "i" (~M68K_SR_IPM_MASK) : "memory");
|
||||
}
|
||||
|
||||
static inline void arch_disable_ints(void) {
|
||||
asm volatile("ori %0, %%sr" :: "i" (M68K_SR_IPM_MASK) : "memory");
|
||||
}
|
||||
|
||||
static inline bool arch_ints_disabled(void) {
|
||||
uint16_t sr;
|
||||
asm volatile("move %%sr, %0" : "=r"(sr) :: "memory");
|
||||
|
||||
// if the IPM is != 0, consider interrupts disabled
|
||||
return (sr & M68K_SR_IPM_MASK);
|
||||
}
|
||||
|
||||
// use a global pointer to store the current_thread
|
||||
extern struct thread *_current_thread;
|
||||
|
||||
static inline struct thread *arch_get_current_thread(void) {
|
||||
return _current_thread;
|
||||
}
|
||||
|
||||
static inline void arch_set_current_thread(struct thread *t) {
|
||||
_current_thread = t;
|
||||
}
|
||||
|
||||
static inline ulong arch_cycle_count(void) { return 0; }
|
||||
|
||||
static inline uint arch_curr_cpu_num(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: see if there's a proper (or required) memory barrier on 68k
|
||||
#define mb() CF
|
||||
#define wmb() CF
|
||||
#define rmb() CF
|
||||
#define smp_mb() CF
|
||||
#define smp_wmb() CF
|
||||
#define smp_rmb() CF
|
||||
|
||||
__END_CDECLS
|
||||
36
arch/m68k/include/arch/arch_thread.h
Normal file
36
arch/m68k/include/arch/arch_thread.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct m68k_context_switch_frame {
|
||||
uint32_t sp;
|
||||
uint32_t pc;
|
||||
|
||||
/* callee saved */
|
||||
uint32_t d2;
|
||||
uint32_t d3;
|
||||
uint32_t d4;
|
||||
uint32_t d5;
|
||||
uint32_t d6;
|
||||
uint32_t d7;
|
||||
uint32_t a2;
|
||||
uint32_t a3;
|
||||
uint32_t a4;
|
||||
uint32_t a5;
|
||||
uint32_t a6;
|
||||
};
|
||||
|
||||
// NOTE: consider using 'state on stack' instead
|
||||
struct arch_thread {
|
||||
struct m68k_context_switch_frame cs_frame;
|
||||
};
|
||||
|
||||
void m68k_context_switch(struct m68k_context_switch_frame *oldcs, struct m68k_context_switch_frame *newcs);
|
||||
|
||||
16
arch/m68k/include/arch/defines.h
Normal file
16
arch/m68k/include/arch/defines.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_SIZE_SHIFT 12
|
||||
|
||||
// XXX is this right?
|
||||
#define CACHE_LINE 32
|
||||
|
||||
#define ARCH_DEFAULT_STACK_SIZE 4096
|
||||
9
arch/m68k/include/arch/m68k.h
Normal file
9
arch/m68k/include/arch/m68k.h
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
62
arch/m68k/include/arch/spinlock.h
Normal file
62
arch/m68k/include/arch/spinlock.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <arch/ops.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if WITH_SMP
|
||||
#error m68k does not support SMP
|
||||
#endif
|
||||
|
||||
#define SPIN_LOCK_INITIAL_VALUE (0)
|
||||
|
||||
typedef unsigned int spin_lock_t;
|
||||
|
||||
typedef unsigned int spin_lock_saved_state_t;
|
||||
typedef unsigned int spin_lock_save_flags_t;
|
||||
|
||||
static inline void arch_spin_lock(spin_lock_t *lock) {
|
||||
*lock = 1;
|
||||
}
|
||||
|
||||
static inline int arch_spin_trylock(spin_lock_t *lock) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void arch_spin_unlock(spin_lock_t *lock) {
|
||||
*lock = 0;
|
||||
}
|
||||
|
||||
static inline void arch_spin_lock_init(spin_lock_t *lock) {
|
||||
*lock = SPIN_LOCK_INITIAL_VALUE;
|
||||
}
|
||||
|
||||
static inline bool arch_spin_lock_held(spin_lock_t *lock) {
|
||||
return *lock != 0;
|
||||
}
|
||||
|
||||
/* default arm flag is to just disable plain irqs */
|
||||
#define ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS 0
|
||||
|
||||
static inline void
|
||||
arch_interrupt_save(spin_lock_saved_state_t *statep, spin_lock_save_flags_t flags) {
|
||||
*statep = arch_ints_disabled();
|
||||
arch_disable_ints();
|
||||
}
|
||||
|
||||
static inline void
|
||||
arch_interrupt_restore(spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags) {
|
||||
if (!old_state) {
|
||||
arch_enable_ints();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
76
arch/m68k/linker.ld
Normal file
76
arch/m68k/linker.ld
Normal file
@@ -0,0 +1,76 @@
|
||||
OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
|
||||
/*
|
||||
* LK linker script for single segment binaries.
|
||||
*/
|
||||
PHDRS
|
||||
{
|
||||
code PT_LOAD FLAGS(5); /* PF_R|PF_X */
|
||||
rodata PT_LOAD FLAGS(4); /* PF_R */
|
||||
data PT_LOAD FLAGS(6); /* PF_R|PF_W */
|
||||
}
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = %KERNEL_BASE% + %KERNEL_LOAD_OFFSET%;
|
||||
|
||||
_start = .;
|
||||
|
||||
/* text/read-only data */
|
||||
/* set the load address to physical MEMBASE */
|
||||
.text : AT(%MEMBASE% + %KERNEL_LOAD_OFFSET%) {
|
||||
KEEP(*(.text.boot))
|
||||
*(.text .text*)
|
||||
*(.gnu.linkonce.t.*)
|
||||
} :code
|
||||
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.rodata : {
|
||||
__rodata_start = .;
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
} :rodata
|
||||
|
||||
/* trick to force any extra sections to be emitted here */
|
||||
. = .;
|
||||
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.data : {
|
||||
__data_start = .;
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
__ctor_list = .;
|
||||
KEEP(*(.ctors .init_array))
|
||||
__ctor_end = .;
|
||||
__dtor_list = .;
|
||||
KEEP(*(.dtors .fini_array))
|
||||
__dtor_end = .;
|
||||
*(.got*)
|
||||
*(.dynamic)
|
||||
} :data
|
||||
|
||||
. = ALIGN(32 / 8);
|
||||
__data_end = .;
|
||||
__bss_start = .;
|
||||
|
||||
/* uninitialized data (in same segment as writable data) */
|
||||
.bss : {
|
||||
/* regular bss */
|
||||
*(.bss .bss.*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
}
|
||||
|
||||
. = ALIGN(32 / 8);
|
||||
__bss_end = .;
|
||||
|
||||
/* Align the end to ensure anything after the kernel ends up on its own pages */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
_end = .;
|
||||
|
||||
. = %KERNEL_BASE% + %MEMSIZE%;
|
||||
_end_of_ram = .;
|
||||
|
||||
/* Strip unnecessary stuff */
|
||||
/DISCARD/ : { *(.comment .note .eh_frame) }
|
||||
}
|
||||
|
||||
64
arch/m68k/rules.mk
Normal file
64
arch/m68k/rules.mk
Normal file
@@ -0,0 +1,64 @@
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
MODULE := $(LOCAL_DIR)
|
||||
|
||||
MODULE_SRCS += \
|
||||
$(LOCAL_DIR)/arch.c \
|
||||
$(LOCAL_DIR)/asm.S \
|
||||
$(LOCAL_DIR)/exceptions.c \
|
||||
$(LOCAL_DIR)/exceptions_asm.S \
|
||||
$(LOCAL_DIR)/start.S \
|
||||
$(LOCAL_DIR)/thread.c \
|
||||
|
||||
# $(LOCAL_DIR)/asm.S \
|
||||
$(LOCAL_DIR)/cache.c \
|
||||
$(LOCAL_DIR)/cache-ops.S \
|
||||
$(LOCAL_DIR)/ops.S \
|
||||
$(LOCAL_DIR)/mmu.c \
|
||||
$(LOCAL_DIR)/faults.c \
|
||||
$(LOCAL_DIR)/descriptor.c
|
||||
|
||||
GLOBAL_DEFINES += \
|
||||
SMP_MAX_CPUS=1
|
||||
|
||||
# set the default toolchain to microblaze elf and set a #define
|
||||
ifndef TOOLCHAIN_PREFIX
|
||||
TOOLCHAIN_PREFIX := m68k-elf-
|
||||
endif
|
||||
|
||||
WITH_LINKER_GC ?= 0
|
||||
|
||||
ARCH_COMPILEFLAGS := -mcpu=68040
|
||||
|
||||
LIBGCC := $(shell $(TOOLCHAIN_PREFIX)gcc $(GLOBAL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(GLOBAL_COMPILEFLAGS) -print-libgcc-file-name)
|
||||
$(info LIBGCC = $(LIBGCC))
|
||||
|
||||
cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc /dev/null 2>&1`"; \
|
||||
then echo "$(2)"; else echo "$(3)"; fi ;)
|
||||
|
||||
ARCH_OPTFLAGS := -O2
|
||||
|
||||
KERNEL_BASE ?= $(MEMBASE)
|
||||
KERNEL_LOAD_OFFSET ?= 0
|
||||
|
||||
GLOBAL_DEFINES += \
|
||||
MEMBASE=$(MEMBASE) \
|
||||
MEMSIZE=$(MEMSIZE)
|
||||
|
||||
# potentially generated files that should be cleaned out with clean make rule
|
||||
GENERATED += \
|
||||
$(BUILDDIR)/linker.ld
|
||||
|
||||
# rules for generating the linker
|
||||
$(BUILDDIR)/linker.ld: $(LOCAL_DIR)/linker.ld $(wildcard arch/*.ld) linkerscript.phony
|
||||
@echo generating $@
|
||||
@$(MKDIR)
|
||||
$(NOECHO)sed "s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/;s/%KERNEL_BASE%/$(KERNEL_BASE)/;s/%KERNEL_LOAD_OFFSET%/$(KERNEL_LOAD_OFFSET)/" < $< > $@.tmp
|
||||
@$(call TESTANDREPLACEFILE,$@.tmp,$@)
|
||||
|
||||
linkerscript.phony:
|
||||
.PHONY: linkerscript.phony
|
||||
|
||||
LINKER_SCRIPT += $(BUILDDIR)/linker.ld
|
||||
|
||||
include make/module.mk
|
||||
33
arch/m68k/start.S
Normal file
33
arch/m68k/start.S
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/asm.h>
|
||||
|
||||
.section .text.boot
|
||||
FUNCTION(_start)
|
||||
// clear bss
|
||||
lea __bss_start,%a0
|
||||
cmpal #_end,%a0
|
||||
beqs 1f
|
||||
0:
|
||||
clrb %a0@+
|
||||
cmpal #_end,%a0
|
||||
bnes 0b
|
||||
1:
|
||||
|
||||
movel #_default_stack_top,%sp
|
||||
jsr lk_main
|
||||
jmp .
|
||||
|
||||
END_FUNCTION(_start)
|
||||
|
||||
.bss
|
||||
.align 8
|
||||
_default_stack_base:
|
||||
.skip 4096
|
||||
_default_stack_top:
|
||||
|
||||
64
arch/m68k/thread.c
Normal file
64
arch/m68k/thread.c
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/debug.h>
|
||||
#include <lk/trace.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <arch/m68k.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
struct thread *_current_thread;
|
||||
|
||||
static void initial_thread_func(void) __NO_RETURN;
|
||||
static void initial_thread_func(void) {
|
||||
thread_t *ct = get_current_thread();
|
||||
|
||||
#if LOCAL_TRACE
|
||||
LTRACEF("thread %p calling %p with arg %p\n", ct, ct->entry, ct->arg);
|
||||
dump_thread(ct);
|
||||
#endif
|
||||
|
||||
/* release the thread lock that was implicitly held across the reschedule */
|
||||
spin_unlock(&thread_lock);
|
||||
arch_enable_ints();
|
||||
|
||||
int ret = ct->entry(ct->arg);
|
||||
|
||||
LTRACEF("thread %p exiting with %d\n", ct, ret);
|
||||
|
||||
thread_exit(ret);
|
||||
}
|
||||
|
||||
void arch_thread_initialize(thread_t *t) {
|
||||
LTRACEF("t %p (%s)\n", t, t->name);
|
||||
|
||||
/* zero out the thread context */
|
||||
memset(&t->arch.cs_frame, 0, sizeof(t->arch.cs_frame));
|
||||
|
||||
t->arch.cs_frame.sp = (vaddr_t)t->stack + t->stack_size;
|
||||
t->arch.cs_frame.pc = (vaddr_t)&initial_thread_func;
|
||||
}
|
||||
|
||||
void arch_context_switch(thread_t *oldthread, thread_t *newthread) {
|
||||
LTRACEF("old %p (%s), new %p (%s)\n", oldthread, oldthread->name, newthread, newthread->name);
|
||||
|
||||
m68k_context_switch(&oldthread->arch.cs_frame, &newthread->arch.cs_frame);
|
||||
}
|
||||
|
||||
void arch_dump_thread(thread_t *t) {
|
||||
#if 0
|
||||
if (t->state != THREAD_RUNNING) {
|
||||
dprintf(INFO, "\tarch: ");
|
||||
dprintf(INFO, "sp 0x%x\n", t->arch.cs_frame.r1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
129
platform/qemu-virt-m68k/goldfish_rtc.c
Normal file
129
platform/qemu-virt-m68k/goldfish_rtc.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include "platform_p.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <lk/err.h>
|
||||
#include <lk/debug.h>
|
||||
#include <lk/reg.h>
|
||||
#include <lk/trace.h>
|
||||
#include <kernel/debug.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <platform/interrupts.h>
|
||||
#include <platform/virt.h>
|
||||
#include <platform/timer.h>
|
||||
#include <platform.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
// implementation of RTC at
|
||||
// https://github.com/qemu/qemu/blob/master/hw/rtc/goldfish_rtc.c
|
||||
volatile unsigned int * const goldfish_rtc_base = (void *)VIRT_GF_RTC_MMIO_BASE;
|
||||
|
||||
// registers
|
||||
enum {
|
||||
RTC_TIME_LOW = 0x00,
|
||||
RTC_TIME_HIGH = 0x04,
|
||||
RTC_ALARM_LOW = 0x08,
|
||||
RTC_ALARM_HIGH = 0x0c,
|
||||
RTC_IRQ_ENABLED = 0x10,
|
||||
RTC_CLEAR_ALARM = 0x14,
|
||||
RTC_ALARM_STATUS = 0x18,
|
||||
RTC_CLEAR_INTERRUPT = 0x1c,
|
||||
};
|
||||
|
||||
static uint64_t system_boot_offset;
|
||||
|
||||
static platform_timer_callback t_callback;
|
||||
static void *t_arg;
|
||||
|
||||
static void write_reg(int reg, uint32_t val) {
|
||||
goldfish_rtc_base[reg / 4] = val;
|
||||
}
|
||||
|
||||
static uint32_t read_reg(int reg) {
|
||||
return goldfish_rtc_base[reg / 4];
|
||||
}
|
||||
|
||||
// raw time from the RTC is ns wall time
|
||||
static uint64_t read_raw_time(void) {
|
||||
uint32_t low, high;
|
||||
|
||||
// read both registers and assemble a 64bit counter
|
||||
// reading low first latches a shadow high register which will prevent wraparound
|
||||
low = read_reg(RTC_TIME_LOW);
|
||||
high = read_reg(RTC_TIME_HIGH);
|
||||
|
||||
return ((uint64_t)high << 32) | low;
|
||||
}
|
||||
|
||||
enum handler_return rtc_irq(void *unused) {
|
||||
enum handler_return ret = INT_NO_RESCHEDULE;
|
||||
|
||||
write_reg(RTC_CLEAR_ALARM, 1);
|
||||
write_reg(RTC_CLEAR_INTERRUPT, 1);
|
||||
|
||||
if (t_callback) {
|
||||
ret = t_callback(t_arg, current_time());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void goldfish_rtc_early_init(void) {
|
||||
// sample the timer and use it as a offset for system start
|
||||
system_boot_offset = read_raw_time();
|
||||
|
||||
// clear and stop any pending irqs on the timer
|
||||
platform_stop_timer();
|
||||
|
||||
register_int_handler(GOLDFISH_RTC_IRQ, &rtc_irq, NULL);
|
||||
unmask_interrupt(GOLDFISH_RTC_IRQ);
|
||||
|
||||
// its okay to enable the irq since we've cleared the alarm and any pending interrupts
|
||||
write_reg(RTC_IRQ_ENABLED, 1);
|
||||
}
|
||||
|
||||
void goldfish_rtc_init(void) {
|
||||
}
|
||||
|
||||
lk_bigtime_t current_time_hires(void) {
|
||||
uint64_t t = read_raw_time() - system_boot_offset;
|
||||
|
||||
return t / 1000ULL; // ns -> us
|
||||
}
|
||||
|
||||
lk_time_t current_time(void) {
|
||||
uint64_t t = read_raw_time() - system_boot_offset;
|
||||
|
||||
return (lk_time_t)(t / 1000000ULL); // ns -> ms
|
||||
}
|
||||
|
||||
status_t platform_set_oneshot_timer (platform_timer_callback callback, void *arg, lk_time_t interval) {
|
||||
LTRACEF("callback %p, arg %p, interval %u\n", callback, arg, interval);
|
||||
|
||||
t_callback = callback;
|
||||
t_arg = arg;
|
||||
|
||||
uint64_t delta = read_raw_time();
|
||||
delta += interval * 1000000ULL;
|
||||
|
||||
write_reg(RTC_ALARM_HIGH, delta >> 32);
|
||||
write_reg(RTC_ALARM_LOW, delta & 0xffffffff);
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void platform_stop_timer(void) {
|
||||
LTRACE;
|
||||
|
||||
write_reg(RTC_CLEAR_ALARM, 1);
|
||||
write_reg(RTC_CLEAR_INTERRUPT, 1);
|
||||
}
|
||||
|
||||
|
||||
130
platform/qemu-virt-m68k/goldfish_tty.c
Normal file
130
platform/qemu-virt-m68k/goldfish_tty.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/reg.h>
|
||||
#include <lk/trace.h>
|
||||
#include <lib/cbuf.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <platform.h>
|
||||
#include <platform/interrupts.h>
|
||||
#include <platform/debug.h>
|
||||
#include <platform/virt.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "platform_p.h"
|
||||
|
||||
// goldfish tty
|
||||
// from https://github.com/qemu/qemu/blob/master/hw/char/goldfish_tty.c
|
||||
volatile unsigned int * const goldfish_tty_base = (void *)VIRT_GF_TTY_MMIO_BASE;
|
||||
|
||||
// registers
|
||||
enum {
|
||||
REG_PUT_CHAR = 0x00,
|
||||
REG_BYTES_READY = 0x04,
|
||||
REG_CMD = 0x08,
|
||||
REG_DATA_PTR = 0x10,
|
||||
REG_DATA_LEN = 0x14,
|
||||
REG_DATA_PTR_HIGH = 0x18,
|
||||
REG_VERSION = 0x20,
|
||||
};
|
||||
|
||||
// commands
|
||||
|
||||
enum {
|
||||
CMD_INT_DISABLE = 0x00,
|
||||
CMD_INT_ENABLE = 0x01,
|
||||
CMD_WRITE_BUFFER = 0x02,
|
||||
CMD_READ_BUFFER = 0x03,
|
||||
};
|
||||
|
||||
#define RXBUF_SIZE 128
|
||||
static char uart_rx_buf_data[RXBUF_SIZE];
|
||||
static cbuf_t uart_rx_buf;
|
||||
|
||||
static char transfer_buf[1]; // static pointer used to transfer MMIO data
|
||||
|
||||
static void write_reg(int reg, uint32_t val) {
|
||||
goldfish_tty_base[reg / 4] = val;
|
||||
}
|
||||
|
||||
static uint32_t read_reg(int reg) {
|
||||
return goldfish_tty_base[reg / 4];
|
||||
}
|
||||
|
||||
static enum handler_return uart_irq_handler(void *arg) {
|
||||
bool resched = false;
|
||||
|
||||
// use a DMA read of one byte if a byte is ready
|
||||
if (read_reg(REG_BYTES_READY) > 0) {
|
||||
write_reg(REG_CMD, CMD_READ_BUFFER);
|
||||
char c = transfer_buf[0];
|
||||
cbuf_write_char(&uart_rx_buf, c, false);
|
||||
resched = true;
|
||||
}
|
||||
|
||||
return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
|
||||
}
|
||||
|
||||
void goldfish_tty_early_init(void) {
|
||||
// make sure irqs are disabled
|
||||
write_reg(REG_CMD, CMD_INT_DISABLE);
|
||||
|
||||
// set up the transfer buffer for receives
|
||||
write_reg(REG_DATA_PTR, (uint32_t)transfer_buf);
|
||||
write_reg(REG_DATA_PTR_HIGH, 0);
|
||||
write_reg(REG_DATA_LEN, sizeof(transfer_buf));
|
||||
}
|
||||
|
||||
void goldfish_tty_init(void) {
|
||||
/* finish uart init to get rx going */
|
||||
cbuf_initialize_etc(&uart_rx_buf, RXBUF_SIZE, uart_rx_buf_data);
|
||||
|
||||
register_int_handler(GOLDFISH_TTY_IRQ, uart_irq_handler, NULL);
|
||||
|
||||
unmask_interrupt(GOLDFISH_TTY_IRQ);
|
||||
|
||||
write_reg(REG_CMD, CMD_INT_ENABLE);
|
||||
}
|
||||
|
||||
void uart_putc(char c) {
|
||||
write_reg(REG_PUT_CHAR, c);
|
||||
}
|
||||
|
||||
int uart_getc(char *c, bool wait) {
|
||||
#if 1
|
||||
return cbuf_read_char(&uart_rx_buf, c, wait);
|
||||
#else
|
||||
return platform_pgetc(c, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void platform_dputc(char c) {
|
||||
if (c == '\n')
|
||||
platform_dputc('\r');
|
||||
uart_putc(c);
|
||||
}
|
||||
|
||||
int platform_dgetc(char *c, bool wait) {
|
||||
int ret = uart_getc(c, wait);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* panic-time getc/putc */
|
||||
void platform_pputc(char c) {
|
||||
return uart_putc(c);
|
||||
}
|
||||
|
||||
int platform_pgetc(char *c, bool wait) {
|
||||
// use a DMA read of one byte if a byte is ready
|
||||
if (read_reg(REG_BYTES_READY) > 0) {
|
||||
write_reg(REG_CMD, CMD_READ_BUFFER);
|
||||
*c = transfer_buf[0];
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
67
platform/qemu-virt-m68k/include/platform/virt.h
Normal file
67
platform/qemu-virt-m68k/include/platform/virt.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// Top level #defines for the 68k-virt machine in qemu 6.0
|
||||
//
|
||||
// From qemu/hw/m68k/virt.c
|
||||
|
||||
/*
|
||||
* 6 goldfish-pic for CPU IRQ #1 to IRQ #6
|
||||
* CPU IRQ #1 -> PIC #1
|
||||
* IRQ #1 to IRQ #31 -> unused
|
||||
* IRQ #32 -> goldfish-tty
|
||||
* CPU IRQ #2 -> PIC #2
|
||||
* IRQ #1 to IRQ #32 -> virtio-mmio from 1 to 32
|
||||
* CPU IRQ #3 -> PIC #3
|
||||
* IRQ #1 to IRQ #32 -> virtio-mmio from 33 to 64
|
||||
* CPU IRQ #4 -> PIC #4
|
||||
* IRQ #1 to IRQ #32 -> virtio-mmio from 65 to 96
|
||||
* CPU IRQ #5 -> PIC #5
|
||||
* IRQ #1 to IRQ #32 -> virtio-mmio from 97 to 128
|
||||
* CPU IRQ #6 -> PIC #6
|
||||
* IRQ #1 -> goldfish-rtc
|
||||
* IRQ #2 to IRQ #32 -> unused
|
||||
* CPU IRQ #7 -> NMI
|
||||
*/
|
||||
#define NUM_PICS 6
|
||||
#define NUM_IRQS (NUM_PICS * 32) // PIC 1 - 6
|
||||
|
||||
#define PIC_IRQ_TO_LINEAR(pic, irq) (((pic) - 1) * 32 + ((irq) - 1))
|
||||
#define GOLDFISH_TTY_IRQ PIC_IRQ_TO_LINEAR(1, 32) // PIC 1, irq 32
|
||||
#define GOLDFISH_RTC_IRQ PIC_IRQ_TO_LINEAR(6, 1) // PIC 6, irq 1
|
||||
|
||||
//#define PIC_IRQ_BASE(num) (8 + (num - 1) * 32)
|
||||
//#define PIC_IRQ(num, irq) (PIC_IRQ_BASE(num) + irq - 1)
|
||||
//#define PIC_GPIO(pic_irq) (qdev_get_gpio_in(pic_dev[(pic_irq - 8) / 32], (pic_irq - 8) % 32))
|
||||
|
||||
#define VIRT_GF_PIC_MMIO_BASE 0xff000000 /* MMIO: 0xff000000 - 0xff005fff */
|
||||
#define VIRT_GF_PIC_IRQ_BASE 1 /* IRQ: #1 -> #6 */
|
||||
#define VIRT_GF_PIC_NB 6
|
||||
|
||||
/* 2 goldfish-rtc (and timer) */
|
||||
#define VIRT_GF_RTC_MMIO_BASE 0xff006000 /* MMIO: 0xff006000 - 0xff007fff */
|
||||
#define VIRT_GF_RTC_IRQ_BASE PIC_IRQ(6, 1) /* PIC: #6, IRQ: #1 */
|
||||
#define VIRT_GF_RTC_NB 2
|
||||
|
||||
/* 1 goldfish-tty */
|
||||
#define VIRT_GF_TTY_MMIO_BASE 0xff008000 /* MMIO: 0xff008000 - 0xff008fff */
|
||||
#define VIRT_GF_TTY_IRQ_BASE PIC_IRQ(1, 32) /* PIC: #1, IRQ: #32 */
|
||||
|
||||
/* 1 virt-ctrl */
|
||||
#define VIRT_CTRL_MMIO_BASE 0xff009000 /* MMIO: 0xff009000 - 0xff009fff */
|
||||
#define VIRT_CTRL_IRQ_BASE PIC_IRQ(1, 1) /* PIC: #1, IRQ: #1 */
|
||||
|
||||
/*
|
||||
* virtio-mmio size is 0x200 bytes
|
||||
* we use 4 goldfish-pic to attach them,
|
||||
* we can attach 32 virtio devices / goldfish-pic
|
||||
* -> we can manage 32 * 4 = 128 virtio devices
|
||||
*/
|
||||
#define VIRT_VIRTIO_MMIO_BASE 0xff010000 /* MMIO: 0xff010000 - 0xff01ffff */
|
||||
#define VIRT_VIRTIO_IRQ_BASE PIC_IRQ(2, 1) /* PIC: 2, 3, 4, 5, IRQ: ALL */
|
||||
130
platform/qemu-virt-m68k/pic.c
Normal file
130
platform/qemu-virt-m68k/pic.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include "platform_p.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <lk/bits.h>
|
||||
#include <lk/err.h>
|
||||
#include <lk/debug.h>
|
||||
#include <lk/reg.h>
|
||||
#include <lk/trace.h>
|
||||
#include <kernel/debug.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <platform/interrupts.h>
|
||||
#include <platform/virt.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
// implementation of PIC at
|
||||
// https://github.com/qemu/qemu/blob/master/hw/intc/goldfish_pic.c
|
||||
|
||||
enum {
|
||||
REG_STATUS = 0x00,
|
||||
REG_IRQ_PENDING = 0x04,
|
||||
REG_IRQ_DISABLE_ALL = 0x08,
|
||||
REG_DISABLE = 0x0c,
|
||||
REG_ENABLE = 0x10,
|
||||
};
|
||||
|
||||
volatile unsigned int * const goldfish_pic_base = (void *)VIRT_GF_PIC_MMIO_BASE;
|
||||
|
||||
static struct int_handlers {
|
||||
int_handler handler;
|
||||
void *arg;
|
||||
} handlers[NUM_IRQS];
|
||||
|
||||
static void write_reg(int pic, int reg, uint32_t val) {
|
||||
goldfish_pic_base[0x1000 * pic / 4 + reg / 4] = val;
|
||||
}
|
||||
|
||||
static uint32_t read_reg(int pic, int reg) {
|
||||
return goldfish_pic_base[0x1000 * pic / 4 + reg / 4];
|
||||
}
|
||||
|
||||
static void dump_pic(int i) {
|
||||
dprintf(INFO, "PIC %d: status %u pending %#x\n", i, read_reg(i, REG_STATUS), read_reg(i, REG_IRQ_PENDING));
|
||||
}
|
||||
|
||||
static void dump_all_pics(void) {
|
||||
for (int i = 0; i < NUM_PICS; i++) {
|
||||
dump_pic(i);
|
||||
}
|
||||
}
|
||||
|
||||
static int irq_to_pic_num(unsigned int vector) {
|
||||
return vector / 32;
|
||||
}
|
||||
|
||||
static int irq_to_pic_vec(unsigned int vector) {
|
||||
return vector % 32;
|
||||
}
|
||||
|
||||
void pic_early_init(void) {
|
||||
}
|
||||
|
||||
void pic_init(void) {
|
||||
dump_all_pics();
|
||||
}
|
||||
|
||||
status_t mask_interrupt(unsigned int vector) {
|
||||
LTRACEF("vector %u\n", vector);
|
||||
write_reg(irq_to_pic_num(vector), REG_DISABLE, 1U << irq_to_pic_vec(vector));
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t unmask_interrupt(unsigned int vector) {
|
||||
LTRACEF("vector %u\n", vector);
|
||||
write_reg(irq_to_pic_num(vector), REG_ENABLE, 1U << irq_to_pic_vec(vector));
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void register_int_handler(unsigned int vector, int_handler handler, void *arg) {
|
||||
LTRACEF("vector %u handler %p arg %p\n", vector, handler, arg);
|
||||
|
||||
DEBUG_ASSERT(vector < NUM_IRQS);
|
||||
|
||||
handlers[vector].handler = handler;
|
||||
handlers[vector].arg = arg;
|
||||
}
|
||||
|
||||
enum handler_return m68k_platform_irq(uint8_t m68k_irq) {
|
||||
LTRACEF("m68k irq vector %d\n", m68k_irq);
|
||||
|
||||
// translate m68k irqs to pic numbers
|
||||
int pic_num;
|
||||
if (likely(m68k_irq >= 1 && m68k_irq <= 6)) {
|
||||
pic_num = m68k_irq - 1;
|
||||
} else {
|
||||
panic("unhandled irq %d from cpu\n", m68k_irq);
|
||||
}
|
||||
|
||||
// see what is pending
|
||||
uint32_t pending = read_reg(pic_num, REG_IRQ_PENDING);
|
||||
if (pending == 0) {
|
||||
// spurious
|
||||
return INT_NO_RESCHEDULE;
|
||||
}
|
||||
|
||||
// find the lowest numbered bit set
|
||||
uint vector = ctz(pending) + pic_num * 32;
|
||||
LTRACEF("pic %d pending %#x vector %u\n", pic_num, pending, vector);
|
||||
|
||||
THREAD_STATS_INC(interrupts);
|
||||
KEVLOG_IRQ_ENTER(vector);
|
||||
|
||||
enum handler_return ret = INT_NO_RESCHEDULE;
|
||||
if (handlers[vector].handler) {
|
||||
ret = handlers[vector].handler(handlers[vector].arg);
|
||||
}
|
||||
|
||||
// no need to ack the interrupt controller since all irqs are implicitly level
|
||||
KEVLOG_IRQ_EXIT(vector);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
178
platform/qemu-virt-m68k/platform.c
Normal file
178
platform/qemu-virt-m68k/platform.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/reg.h>
|
||||
#include <lk/trace.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <platform.h>
|
||||
#include <platform/interrupts.h>
|
||||
#include <platform/debug.h>
|
||||
#include <platform/timer.h>
|
||||
#include <platform/virt.h>
|
||||
#include <sys/types.h>
|
||||
#include <dev/virtio.h>
|
||||
#include <dev/virtio/net.h>
|
||||
#if WITH_LIB_MINIP
|
||||
#include <lib/minip.h>
|
||||
#endif
|
||||
#if WITH_KERNEL_VM
|
||||
#include <kernel/vm.h>
|
||||
#else
|
||||
#include <kernel/novm.h>
|
||||
#endif
|
||||
#if WITH_LIB_CONSOLE
|
||||
#include <lib/console.h>
|
||||
#endif
|
||||
|
||||
#include "platform_p.h"
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
extern ulong lk_boot_args[4];
|
||||
|
||||
#if WITH_KERNEL_VM
|
||||
#define DEFAULT_MEMORY_SIZE (MEMSIZE) /* try to fetch from the emulator via the fdt */
|
||||
|
||||
static pmm_arena_t arena = {
|
||||
.name = "ram",
|
||||
.base = MEMORY_BASE_PHYS,
|
||||
.size = DEFAULT_MEMORY_SIZE,
|
||||
.flags = PMM_ARENA_FLAG_KMAP,
|
||||
};
|
||||
#endif
|
||||
|
||||
void platform_early_init(void) {
|
||||
goldfish_tty_early_init();
|
||||
pic_early_init();
|
||||
goldfish_rtc_early_init();
|
||||
#if 0
|
||||
plic_early_init();
|
||||
|
||||
LTRACEF("starting FDT scan\n");
|
||||
|
||||
/* look for a flattened device tree in the second arg passed to us */
|
||||
bool found_mem = false;
|
||||
int cpu_count = 0;
|
||||
const void *fdt = (void *)lk_boot_args[1];
|
||||
#if WITH_KERNEL_VM
|
||||
fdt = (const void *)((uintptr_t)fdt + PERIPHERAL_BASE_VIRT);
|
||||
#endif
|
||||
|
||||
struct fdt_walk_callbacks cb = {
|
||||
.mem = memcallback,
|
||||
.memcookie = &found_mem,
|
||||
.cpu = cpucallback,
|
||||
.cpucookie = &cpu_count,
|
||||
};
|
||||
|
||||
status_t err = fdt_walk(fdt, &cb);
|
||||
LTRACEF("fdt_walk returns %d\n", err);
|
||||
|
||||
if (err != 0) {
|
||||
printf("FDT: error finding FDT at %p, using default memory & cpu count\n", fdt);
|
||||
}
|
||||
|
||||
if (!found_mem) {
|
||||
#if WITH_KERNEL_VM
|
||||
pmm_add_arena(&arena);
|
||||
#else
|
||||
novm_add_arena("default", MEMBASE, MEMSIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cpu_count > 0) {
|
||||
printf("FDT: found %d cpus\n", cpu_count);
|
||||
riscv_set_secondary_count(cpu_count - 1);
|
||||
}
|
||||
|
||||
#if WITH_KERNEL_VM
|
||||
/* reserve the first 256K of ram which is marked protected by the PMP in firmware */
|
||||
struct list_node list = LIST_INITIAL_VALUE(list);
|
||||
pmm_alloc_range(MEMBASE, 0x40000 / PAGE_SIZE, &list);
|
||||
#endif
|
||||
|
||||
LTRACEF("done scanning FDT\n");
|
||||
|
||||
/* save a copy of the pointer to the poweroff/reset register */
|
||||
/* TODO: read it from the FDT */
|
||||
#if WITH_KERNEL_VM
|
||||
power_reset_reg = paddr_to_kvaddr(0x100000);
|
||||
#else
|
||||
power_reset_reg = (void *)0x100000;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void platform_init(void) {
|
||||
pic_init();
|
||||
goldfish_tty_init();
|
||||
goldfish_rtc_init();
|
||||
#if 0
|
||||
plic_init();
|
||||
uart_init();
|
||||
|
||||
/* detect any virtio devices */
|
||||
uint virtio_irqs[NUM_VIRTIO_TRANSPORTS];
|
||||
for (int i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) {
|
||||
virtio_irqs[i] = IRQ_VIRTIO_BASE + i;
|
||||
}
|
||||
|
||||
virtio_mmio_detect((void *)VIRTIO_BASE_VIRT, NUM_VIRTIO_TRANSPORTS, virtio_irqs, VIRTIO_STRIDE);
|
||||
|
||||
#if WITH_LIB_MINIP
|
||||
if (virtio_net_found() > 0) {
|
||||
uint8_t mac_addr[6];
|
||||
|
||||
virtio_net_get_mac_addr(mac_addr);
|
||||
|
||||
TRACEF("found virtio networking interface\n");
|
||||
|
||||
/* start minip */
|
||||
minip_set_macaddr(mac_addr);
|
||||
|
||||
__UNUSED uint32_t ip_addr = IPV4(192, 168, 0, 99);
|
||||
__UNUSED uint32_t ip_mask = IPV4(255, 255, 255, 0);
|
||||
__UNUSED uint32_t ip_gateway = IPV4_NONE;
|
||||
|
||||
//minip_init(virtio_net_send_minip_pkt, NULL, ip_addr, ip_mask, ip_gateway);
|
||||
minip_init_dhcp(virtio_net_send_minip_pkt, NULL);
|
||||
|
||||
virtio_net_start();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
void platform_halt(platform_halt_action suggested_action,
|
||||
platform_halt_reason reason) {
|
||||
switch (suggested_action) {
|
||||
case HALT_ACTION_SHUTDOWN:
|
||||
dprintf(ALWAYS, "Shutting down... (reason = %d)\n", reason);
|
||||
*power_reset_reg = 0x5555;
|
||||
break;
|
||||
case HALT_ACTION_REBOOT:
|
||||
dprintf(ALWAYS, "Rebooting... (reason = %d)\n", reason);
|
||||
*power_reset_reg = 0x7777;
|
||||
break;
|
||||
case HALT_ACTION_HALT:
|
||||
#if ENABLE_PANIC_SHELL
|
||||
if (reason == HALT_REASON_SW_PANIC) {
|
||||
dprintf(ALWAYS, "CRASH: starting debug shell... (reason = %d)\n", reason);
|
||||
arch_disable_ints();
|
||||
panic_shell_start();
|
||||
}
|
||||
#endif // ENABLE_PANIC_SHELL
|
||||
dprintf(ALWAYS, "HALT: spinning forever... (reason = %d)\n", reason);
|
||||
break;
|
||||
}
|
||||
|
||||
arch_disable_ints();
|
||||
for (;;)
|
||||
arch_idle();
|
||||
}
|
||||
#endif
|
||||
19
platform/qemu-virt-m68k/platform_p.h
Normal file
19
platform/qemu-virt-m68k/platform_p.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
void uart_init(void);
|
||||
|
||||
void pic_early_init(void);
|
||||
void pic_init(void);
|
||||
void goldfish_rtc_early_init(void);
|
||||
void goldfish_rtc_init(void);
|
||||
void goldfish_tty_early_init(void);
|
||||
void goldfish_tty_init(void);
|
||||
27
platform/qemu-virt-m68k/rules.mk
Normal file
27
platform/qemu-virt-m68k/rules.mk
Normal file
@@ -0,0 +1,27 @@
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
MODULE := $(LOCAL_DIR)
|
||||
|
||||
ARCH := m68k
|
||||
LK_HEAP_IMPLEMENTATION ?= dlmalloc
|
||||
|
||||
MODULE_DEPS += lib/cbuf
|
||||
MODULE_DEPS += dev/virtio/block
|
||||
MODULE_DEPS += dev/virtio/gpu
|
||||
MODULE_DEPS += dev/virtio/net
|
||||
|
||||
MODULE_SRCS += $(LOCAL_DIR)/goldfish_rtc.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/goldfish_tty.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/pic.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/platform.c
|
||||
|
||||
MEMBASE ?= 0x00000000
|
||||
MEMSIZE ?= 0x08000000 # default to 128MB
|
||||
|
||||
# we can revert to a poll based uart spin routine
|
||||
GLOBAL_DEFINES += PLATFORM_SUPPORTS_PANIC_SHELL=1
|
||||
|
||||
# our timer supports one shot mode
|
||||
GLOBAL_DEFINES += PLATFORM_HAS_DYNAMIC_TIMER=1
|
||||
|
||||
include make/module.mk
|
||||
9
project/qemu-virt-m68k-test.mk
Normal file
9
project/qemu-virt-m68k-test.mk
Normal file
@@ -0,0 +1,9 @@
|
||||
# main project for qemu-riscv64
|
||||
MODULES += \
|
||||
app/shell
|
||||
|
||||
include project/virtual/test.mk
|
||||
include project/virtual/fs.mk
|
||||
include project/virtual/minip.mk
|
||||
include project/target/qemu-virt-m68k.mk
|
||||
|
||||
2
project/target/qemu-virt-m68k.mk
Normal file
2
project/target/qemu-virt-m68k.mk
Normal file
@@ -0,0 +1,2 @@
|
||||
TARGET := qemu-virt-m68k
|
||||
|
||||
11
scripts/do-qemum68k
Executable file
11
scripts/do-qemum68k
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
PROJECT=qemu-virt-m68k-test
|
||||
|
||||
$DIR/make-parallel $PROJECT
|
||||
qemu-system-m68k -machine virt -cpu m68040 -kernel build-${PROJECT}/lk.elf -nographic $@
|
||||
5
target/qemu-virt-m68k/rules.mk
Normal file
5
target/qemu-virt-m68k/rules.mk
Normal file
@@ -0,0 +1,5 @@
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
MODULE := $(LOCAL_DIR)
|
||||
|
||||
PLATFORM := qemu-virt-m68k
|
||||
@@ -15,6 +15,7 @@ __BEGIN_CDECLS
|
||||
|
||||
#define clz(x) __builtin_clz(x)
|
||||
#define ctz(x) __builtin_ctz(x)
|
||||
#define ffs(x) __builtin_ffs(x)
|
||||
|
||||
#define BIT(x, bit) ((x) & (1UL << (bit)))
|
||||
#define BIT_SHIFT(x, bit) (((x) >> (bit)) & 1)
|
||||
|
||||
Reference in New Issue
Block a user