Merge remote-tracking branch 'handout/main'

This commit is contained in:
Jan Schär 2022-04-05 16:15:08 +02:00
commit 8e56ac9244
29 changed files with 414 additions and 67 deletions

1
.gitignore vendored
View File

@ -49,3 +49,4 @@ bin/
# clang
.clang_complete
compile_commands.json
test-logs

View File

@ -21,6 +21,7 @@
#include <barrelfish_kpi/distcaps.h> // for distcap_state_t
#include <barrelfish_kpi/lmp.h> // invoking lmp endpoint requires flags
#include <barrelfish_kpi/syscalls.h>
#include <barrelfish_kpi/platform.h> // for struct platform info
#include <aos/caddr.h>
#include <barrelfish_kpi/paging_arch.h>
@ -241,4 +242,15 @@ static inline errval_t invoke_vnode_inherit(struct capref dest, capaddr_t src,
newflags, src_mcn, dst_mcn).error;
}
static inline errval_t invoke_kernel_get_platform_info(struct capref kernel_cap, struct platform_info* pi)
{
struct sysret sr = cap_invoke2(kernel_cap, KernelCmd_Get_platform, (lvaddr_t)pi);
if (err_is_fail(sr.error)) {
pi->arch = PI_ARCH_UNKNOWN;
pi->platform = PI_PLATFORM_UNKNOWN;
}
return sr.error;
}
#endif

View File

@ -19,6 +19,7 @@
#include <aos/static_assert.h>
enum pi_arch {
PI_ARCH_UNKNOWN,
PI_ARCH_X86,
PI_ARCH_ARMV7A,
PI_ARCH_ARMV8A,

View File

@ -38,6 +38,7 @@ enum debug_message {
DEBUG_CREATE_IRQ_SRC_CAP,
DEBUG_GET_MDB_SIZE,
DEBUG_PRINT_MDB_COUNTERS,
DEBUG_GET_PLATFORM_INFO,
};
#endif //BARRELFISH_KPI_SYS_DEBUG_H

34
include/drivers/pl011.h Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2020, ETH Zurich.
* Copyright (c) 2022, The University of British Columbia.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
* ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
*/
#ifndef PL011_H_
#define PL011_H_
#include <stdint.h>
#include <aos/aos.h>
//#define PL011_DEBUG_ON
#if defined(PL011_DEBUG_ON)
#define PL011_DEBUG(x...) debug_printf("pl011:" x)
#else
#define PL011_DEBUG(x...) ((void)0)
#endif
#define PL011_UART0_INT 1
struct pl011_s;
errval_t pl011_init(struct pl011_s** s, void *base);
errval_t pl011_enable_interrupt(struct pl011_s * s);
errval_t pl011_putchar(struct pl011_s* s, char c);
errval_t pl011_getchar(struct pl011_s* s, char *c);
#endif

37
include/maps/qemu_map.h Normal file
View File

@ -0,0 +1,37 @@
/**
* \file
* \brief Physical memory map for the QEMU Virt Platform
*/
/*
* Copyright (c) 2022, The University of British Columbia.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
* ETH Zurich D-INFK, CAB F.78, Universitaetstrasse 6, CH-8092 Zurich.
* Attn: Systems Group.
*/
#ifndef QEMU_MAP_H
#define QEMU_MAP_H
#define QEMU_SPI_INTERRUPTS_START 32
/*
* UART
*/
#define QEMU_UART_BASE 0x09000000
#define QEMU_UART_SIZE 0x1000
#define QEMU_UART_INT (QEMU_SPI_INTERRUPTS_START + PL011_UART0_INT)
/*
* GIC Distributor
*/
#define QEMU_GIC_DIST_BASE 0x08000000
#define QEMU_GIC_DIST_SIZE 0x1000
#endif // QEMU_MAP_H

View File

@ -88,7 +88,7 @@ long atol(const char *);
void *bsearch(const void *, const void *, size_t,
size_t, int (*)(const void *, const void *));
void *calloc(size_t, size_t) __malloc_like __result_use_check
__alloc_size(1) __alloc_size(2);
__attribute__((__alloc_size__(1, 2)));
div_t div(int, int) __pure2;
_Noreturn void exit(int);
void free(void *);
@ -303,8 +303,8 @@ void qsort_r(void *, size_t, size_t, void *,
int (*)(void *, const void *, const void *));
int radixsort(const unsigned char **, int, const unsigned char *,
unsigned);
void *reallocarray(void *, size_t, size_t) __result_use_check __alloc_size(2)
__alloc_size(3);
void *reallocarray(void *, size_t, size_t) __result_use_check
__attribute__((__alloc_size__(2, 3)));
void *reallocf(void *, size_t) __alloc_size(2);
int rpmatch(const char *);
void setprogname(const char *);

View File

@ -28,7 +28,8 @@ extern lpaddr_t platform_gic_distributor_base;
// Command line arguments
static struct cmdarg cmdargs[] = {
{"gic", ArgType_UInt, { .uinteger = &platform_gic_cpu_interface_base }},
{"gicdist", ArgType_UInt, { .uinteger = &platform_gic_distributor_base }}
{"gicdist", ArgType_UInt, { .uinteger = &platform_gic_distributor_base }},
{NULL, 0, {NULL}}
};
enum IrqType {

View File

@ -26,7 +26,8 @@ extern lpaddr_t platform_gic_distributor_base;
// Command line arguments
static struct cmdarg cmdargs[] = {
{"gic", ArgType_ULong, { .ulonginteger = &platform_gic_cpu_interface_base }},
{"gicdist", ArgType_ULong, { .ulonginteger = &platform_gic_distributor_base }}
{"gicdist", ArgType_ULong, { .ulonginteger = &platform_gic_distributor_base }},
{NULL, 0, {NULL}}
};
/*

View File

@ -27,7 +27,8 @@ extern lpaddr_t platform_gic_redistributor_base;
// Command line arguments
static struct cmdarg cmdargs[] = {
{"gicdist", ArgType_ULong, { .ulonginteger = &platform_gic_distributor_base }},
{"gicredist", ArgType_ULong, { .ulonginteger = &platform_gic_redistributor_base }}
{"gicredist", ArgType_ULong, { .ulonginteger = &platform_gic_redistributor_base }},
{NULL, 0, {NULL}}
};
/*

View File

@ -525,8 +525,14 @@ caps_map_l3(struct capability* dest,
{
assert(0 == (kpi_paging_flags & ~KPI_PAGING_FLAGS_MASK));
if (slot >= VMSAv8_64_PTABLE_NUM_ENTRIES) {
return SYS_ERR_VNODE_SLOT_INVALID;
// Check slot is valid and mapping does not overlap leaf page table
if (slot + pte_count > VMSAv8_64_PTABLE_NUM_ENTRIES) {
if (slot >= VMSAv8_64_PTABLE_NUM_ENTRIES) {
return SYS_ERR_VNODE_SLOT_INVALID;
}
else {
return SYS_ERR_VM_MAP_SIZE;
}
}
if (src->type != ObjType_Frame && src->type != ObjType_DevFrame) {
@ -539,11 +545,6 @@ caps_map_l3(struct capability* dest,
return SYS_ERR_FRAME_OFFSET_INVALID;
}
// check mapping does not overlap leaf page table
if (slot + pte_count > VMSAv8_64_PTABLE_NUM_ENTRIES ) {
return SYS_ERR_VM_MAP_SIZE;
}
// Destination
lpaddr_t dest_lpaddr = gen_phys_to_local_phys(get_address(dest));
lvaddr_t dest_lvaddr = local_phys_to_mem(dest_lpaddr);
@ -770,7 +771,7 @@ bool paging_is_region_valid(lvaddr_t buffer, size_t size, uint8_t type)
return true;
}
void paging_dump_tables(struct dcb *dispatcher)
void paging_dump_tables(struct dcb *dispatcher, lvaddr_t addr)
{
if (!local_phys_is_valid(dispatcher->vspace)) {
printk(LOG_ERR, "dispatcher->vspace = 0x%"PRIxLPADDR": too high!\n" ,
@ -779,6 +780,68 @@ void paging_dump_tables(struct dcb *dispatcher)
}
lvaddr_t l0 = local_phys_to_mem(dispatcher->vspace);
if (addr < (VMSAv8_64_PTABLE_NUM_ENTRIES * VMSAv8_64_PTABLE_NUM_ENTRIES * HUGE_PAGE_SIZE)) {
uint32_t l0_index = VMSAv8_64_L0_INDEX(addr);
uint32_t l1_index = VMSAv8_64_L1_INDEX(addr);
uint32_t l2_index = VMSAv8_64_L2_INDEX(addr);
uint32_t l3_index = VMSAv8_64_L3_INDEX(addr);
printf("dumping table: %lx -> %u.%u.%u.%u\n", addr, l0_index, l1_index, l2_index, l3_index);
union armv8_ttable_entry *l0_e = (union armv8_ttable_entry *) l0 + l0_index;
if (!l0_e->d.valid) {
printf("l0[% 3d] -> INVALID\n", l0_index);
return;
}
genpaddr_t l1_gp = (genpaddr_t)(l0_e->d.base) << BASE_PAGE_BITS;
lvaddr_t l1 = local_phys_to_mem(gen_phys_to_local_phys(l1_gp));
printf("l0[% 3d] -> l1 @ %p\n", l0_index, l1);
union armv8_ttable_entry *l1_e = (union armv8_ttable_entry *)l1 + l1_index;
if (!l1_e->d.valid) {
printf(" l1[% 3d] -> INVALID\n", l1_index);
return;
}
// super page mapping
if (l1_e->block_l1.mb0 == 0) {
genpaddr_t l2_gp = (genpaddr_t)(l1_e->block_l1.base) << HUGE_PAGE_BITS;
printf(" l1[% 3d] -> HUGE_PAGE @ 0x%lx\n", l1_index, l2_gp);
return;
}
genpaddr_t l2_gp = (genpaddr_t)(l1_e->d.base) << BASE_PAGE_BITS;
lvaddr_t l2 = local_phys_to_mem(gen_phys_to_local_phys(l2_gp));
printf(" l1[% 3d] -> l2 @ %p\n", l1_index, l2);
union armv8_ttable_entry *l2_e = (union armv8_ttable_entry *)l2 + l2_index;
if (!l2_e->d.valid) {
printf(" l2[% 3d] -> INVALID\n", l2_index);
return;
}
if (l2_e->block_l2.mb0 == 0) {
genpaddr_t l3_gp = (genpaddr_t)(l1_e->block_l2.base) << LARGE_PAGE_BITS;
printf(" l2[% 3d] -> LARGE_PAGE @ 0x%lx\n", l1_index, l3_gp);
return;
}
genpaddr_t l3_gp = (genpaddr_t)(l2_e->d.base) << BASE_PAGE_BITS;
lvaddr_t l3 = local_phys_to_mem(gen_phys_to_local_phys(l3_gp));
printf(" l2 [% 3d] -> l3 @ %p\n", l2_index, l3);
union armv8_ttable_entry *l3_e = (union armv8_ttable_entry *)l3 + l3_index;
if (!l3_e->d.valid) {
printf(" l3[% 3d] -> INVALID\n", l3_index);
return;
}
genpaddr_t paddr = (genpaddr_t)(l3_e->page.base) << BASE_PAGE_BITS;
printf(" l3[% 3d] -> BASE_PAGE @ 0x%lx \n", l3_index, paddr);
return;
}
for (int l0_index = 0; l0_index < VMSAv8_64_PTABLE_NUM_ENTRIES; l0_index++) {
// get level0 table
union armv8_ttable_entry *l0_e = (union armv8_ttable_entry *) l0 + l0_index;

View File

@ -153,6 +153,11 @@ uint32_t platform_get_timer_interrupt(void){
// TODO get this right
void platform_get_dev_range(lpaddr_t* start, size_t* size){
*start = 0;
*size = 0;
// the whole platform_get_dev_range is rather a hack.
// to make the Qemu work with the approach of imx8x.
// see: https://github.com/qemu/qemu/blob/master/hw/arm/virt.c
*start = 0x08000000;
*size = 0x01010000; // just include up to the uart
}

View File

@ -866,7 +866,9 @@ static struct sysret dispatcher_dump_ptables(
assert(3 == argc);
struct dcb *dispatcher = to->u.dispatcher.dcb;
paging_dump_tables(dispatcher);
struct registers_aarch64_syscall_args* sa = &context->syscall_args;
paging_dump_tables(dispatcher, sa->arg2);
return SYSRET(SYS_ERR_OK);
}
@ -1328,6 +1330,9 @@ void sys_syscall(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3,
case SYSCALL_NOP:
r.error = SYS_ERR_OK;
break;
case SYSCALL_REBOOT:
psci_system_reset();
break;
case SYSCALL_PRINT:
if (argc == 3) {

View File

@ -145,7 +145,7 @@ errval_t ptable_modify_flags(struct capability *leaf_pt, size_t offset,
errval_t paging_modify_flags(struct capability *frame, uintptr_t offset,
uintptr_t pages, uintptr_t kpi_paging_flags);
void paging_dump_tables_around(struct dcb *dispatcher, lvaddr_t vaddr);
void paging_dump_tables(struct dcb *dispatcher);
void paging_dump_tables(struct dcb *dispatcher, lvaddr_t va);
errval_t caps_retype(enum objtype type, gensize_t objsize, size_t count,
struct capability *dest_cnode, cslot_t dest_slot,

View File

@ -206,7 +206,7 @@ aos_rpc_serial_read(struct aos_rpc *rpc, char *buf, size_t buf_len) {
errval_t
aos_rpc_process_spawn(struct aos_rpc *rpc, char *cmdline,
coreid_t core, domainid_t *newpid) {
// (M5): implement spawn new process rpc
// implement spawn new process rpc
size_t cmdline_size = strlen(cmdline) + 1;
if (cmdline_size > RPC_SHARED_SIZE) return AOS_ERR_RPC_ARG_TOO_BIG;
memcpy(rpc->shared_mem, cmdline, cmdline_size);
@ -225,7 +225,7 @@ aos_rpc_process_spawn(struct aos_rpc *rpc, char *cmdline,
errval_t
aos_rpc_process_get_name(struct aos_rpc *rpc, domainid_t pid, char **name) {
// (M5): implement name lookup for process given a process id
// implement name lookup for process given a process id
size_t name_len;
errval_t err = do_aos_rpc(
rpc, RPC_MTYPE_PROCESS_GET_NAME,
@ -244,7 +244,7 @@ aos_rpc_process_get_name(struct aos_rpc *rpc, domainid_t pid, char **name) {
errval_t
aos_rpc_process_get_all_pids(struct aos_rpc *rpc, domainid_t **pids,
size_t *pid_count) {
// (M5): implement process id discovery
// implement process id discovery
size_t ret_len;
errval_t err = do_aos_rpc(
rpc, RPC_MTYPE_PROCESS_GET_ALL_PIDS,

View File

@ -95,9 +95,9 @@ static inline bool havework_disabled(dispatcher_handle_t handle)
{
struct dispatcher_generic *disp = get_dispatcher_generic(handle);
return disp->runq != NULL
#ifdef CONFIG_INTERCONNECT_DRIVER_LMP
#ifdef CONFIG_INTERCONNECT_DRIVER_LMP
|| disp->lmp_send_events_list != NULL
#endif
#endif
|| disp->polled_channels != NULL
|| disp->notificators != NULL
;

View File

@ -68,7 +68,7 @@ static void pt_exception_handler(enum exception_type type, int subtype,
{
lvaddr_t ip = registers_get_ip(regs);
debug_printf("Page Fault: type=%s, addr=%p, ip=%p\n",
debug_printf("Page Fault: type=%s, addr=%p, ip=%p\n",
pt_exception_type_to_string(type, subtype),
addr,
ip
@ -384,7 +384,6 @@ errval_t paging_init_state_foreign(struct paging_state *st, lvaddr_t start_vaddr
errval_t paging_init_params(struct spawn_domain_params *params)
{
errval_t err;
debug_printf("paging_init\n");
// (M2): Call paging_init_state for &current
// TODO (M4): initialize self-paging handler
// TIP: use thread_set_exception_handler() to setup a page fault handler
@ -624,7 +623,6 @@ errval_t paging_map_frame_attr(struct paging_state *st, void **buf, size_t bytes
return paging_map_fixed_attr(st, (lvaddr_t) *buf, frame, bytes, flags);
}
/**
* @brief mapps the provided frame at the supplied address in the paging state
*
@ -795,8 +793,6 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr,
* @return SYS_ERR_OK on success, or error code indicating the kind of failure
*
* The supplied `region` must be the start of a previously mapped frame.
*
* @NOTE: Implementing this function is optional.
*/
errval_t paging_unmap(struct paging_state *st, const void *region)
{

View File

@ -180,56 +180,49 @@ size_t slab_freecount(struct slab_allocator *slabs)
errval_t slab_refill_pages(struct slab_allocator *slabs, size_t bytes)
{
errval_t err;
// Hint: you can't just use malloc here...
// Hint: For M1, just use the fixed mapping funcionality, however you may want to replace
// the fixed mapping later to avoid conflicts.
struct capref cap;
struct capref frame;
err = slot_alloc(&frame);
err = slot_alloc(&cap);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_SLOT_ALLOC);
}
err = slab_refill_no_pagefault(slabs, frame, bytes);
err = slab_refill_no_pagefault(slabs, cap, bytes);
if (err_is_fail(err)) {
slot_free(frame);
return err;
slot_free(cap);
}
return SYS_ERR_OK;
return err;
}
/**
* @brief refills the slab allocator without causing a page fault
*
* @param slabs the slab allocator to be refilled
* @param frame an empty slot to hold the frame capability
* @param minbytes the minimum about of bytes to refill
* @param slabs the slab allocator to be refilled
* @param frame_slot an empty capability slot for the frames
* @param minbytes the minimum number of bytes to allocate
*
* @return SYS_ERR_OK on success, errval on failure
*
* Note, the frame here is an empty slot that can be used as storage for a frame.
* @return SYS_ERR_OK on success, error code on failure
*/
errval_t slab_refill_no_pagefault(struct slab_allocator *slabs, struct capref frame,
errval_t slab_refill_no_pagefault(struct slab_allocator *slabs, struct capref frame_slot,
size_t minbytes)
{
// Refill the slot allocator without causing a page fault
// Hint: you can't just use malloc here...
// Refill the slot allocator without causing a page-fault
errval_t err;
size_t alloc_bytes;
err = frame_create(frame, minbytes, &alloc_bytes);
err = frame_create(frame_slot, minbytes, &alloc_bytes);
if (err_is_fail(err)) return err_push(err, LIB_ERR_FRAME_ALLOC);
struct paging_state *paging_state = get_current_paging_state();
void *vaddr = NULL;
err = paging_map_frame_attr(
paging_state, &vaddr,
alloc_bytes, frame, VREGION_FLAGS_READ_WRITE
alloc_bytes, frame_slot, VREGION_FLAGS_READ_WRITE
);
if (err_is_fail(err)) {
// TODO: free the RAM, but without freeing the frame slot
cap_delete(frame);
cap_delete(frame_slot);
return err;
}

View File

@ -70,6 +70,8 @@ errval_t slot_alloc_root(struct capref *ret)
}
state->rootca.refilling = false;
}
// If we got below two here somehow it's game over
assert(rootcn_free > 2);
struct slot_allocator *ca = (struct slot_allocator*)(&state->rootca);
return ca->alloc(ca, ret);
}

View File

@ -64,6 +64,8 @@ errval_t two_level_alloc(struct slot_allocator *ca, struct capref *ret)
struct slot_alloc_state *state = get_slot_alloc_state();
struct slot_allocator *rca = (struct slot_allocator *)(&state->rootca);
// Need to refill when one slot left, otherwise it's too late
// We can't leave it at one though either as the code in slot_alloc_root()
// assumes there are always at least 2 slots left, so refill at 2 or less
size_t rootcn_free = single_slot_alloc_freecount(&state->rootca);
if (rootcn_free <= 2) {
// resize root slot allocator (and rootcn)

View File

@ -6,16 +6,16 @@
#include <stdlib.h>
#include <assert.h>
size_t (*_libc_terminal_read_func)(char *, size_t);
size_t (*_libc_terminal_write_func)(const char *, size_t);
extern size_t (*_libc_terminal_read_func)(char *, size_t);
extern size_t (*_libc_terminal_write_func)(const char *, size_t);
void (*_libc_assert_func)(const char *, const char *, const char *, int);
typedef void *(*morecore_alloc_func_t)(size_t bytes, size_t *retbytes);
morecore_alloc_func_t sys_morecore_alloc;
extern morecore_alloc_func_t sys_morecore_alloc;
typedef void (*morecore_free_func_t)(void *base, size_t bytes);
morecore_free_func_t sys_morecore_free;
extern morecore_free_func_t sys_morecore_free;
int system(const char *cmd)
{

View File

@ -309,6 +309,7 @@ static errval_t spawn_serialize_vspace(struct spawninfo *si, struct paging_state
}
/**
* (M2): Implement this function.
* \brief Spawn a new dispatcher called 'argv[0]' with 'argc' arguments.

View File

@ -28,6 +28,13 @@ mkdir -p $BF_BUILD
# run the command in the docker image with the same userid to avoid
# permission problems later.
docker run -u $(id -u) --rm -i -t \
--mount type=bind,source=$BF_SOURCE,target=/source \
$BF_DOCKER
if [[ "$@" == "" ]]; then
docker run -u $(id -u) --rm -i -t \
--mount type=bind,source=$BF_SOURCE,target=/source \
$BF_DOCKER
else
docker run -u $(id -u) --rm \
--mount type=bind,source=$BF_SOURCE,target=/source \
$BF_DOCKER "$@"
fi

View File

@ -18,8 +18,8 @@ build: Dockerfile install.sh entrypoint.sh
docker build -t $(IMAGE_NAME):$(IMAGE_TAG) .
publish: build
docker tag $(IMAGE_NAME):20.04-lts-aos $(DOCKER_HUB_USER)/$(IMAGE_NAME):$(IMAGE_TAG)
docker tag $(IMAGE_NAME):20.04-lts-aos $(DOCKER_HUB_USER)/$(IMAGE_NAME):latest
docker tag $(IMAGE_NAME):$(IMAGE_TAG) $(DOCKER_HUB_USER)/$(IMAGE_NAME):$(IMAGE_TAG)
docker tag $(IMAGE_NAME):$(IMAGE_TAG) $(DOCKER_HUB_USER)/$(IMAGE_NAME):latest
docker push $(DOCKER_HUB_USER)/$(IMAGE_NAME):$(IMAGE_TAG)
test:

View File

@ -1,11 +1,16 @@
#!/bin/bash
# Copyright (c) 2021 The University of British Columbia.
# Copyright (c) 2021,2022 The University of British Columbia.
# All rights reserved.
#
# This file is distributed under the terms in the attached LICENSE file.
cd /source
# create the build directory if it doesn't exist
mkdir -p /source/build
# cd into the build directory
cd /source/build
if [ "$1" == "" ]; then
exec "/bin/bash"

View File

@ -14,7 +14,7 @@ DEBIAN_FRONTEND=noninteractive apt-get install -y \
python3 parted wget mtools
# install barrelfish dependencies
apt-get update
apt-get update && apt-get upgrade
DEBIAN_FRONTEND=noninteractive apt-get install -y \
build-essential bison flex ghc libghc-src-exts-dev \
libghc-ghc-paths-dev libghc-parsec3-dev libghc-random-dev\
@ -27,6 +27,10 @@ DEBIAN_FRONTEND=noninteractive apt-get install -y \
cabal v1-update
cabal v1-install --global bytestring-trie
# install the autograder dependencies
DEBIAN_FRONTEND=noninteractive apt-get install -y \
python3 python3-pexpect python3-plumbum
# get the uuu tool
wget -P /bin https://github.com/NXPmicro/mfgtools/releases/download/uuu_1.4.165/uuu
chmod 755 /bin/uuu
@ -39,4 +43,4 @@ chmod 755 /source
apt-get clean && apt-get autoclean && apt-get autoremove -y
# make sure it's executable
chmod 755 /entrypoint.sh
chmod 755 /entrypoint.sh

View File

@ -0,0 +1,19 @@
--------------------------------------------------------------------------
-- Copyright (c) 2020, ETH Zurich.
-- All rights reserved.
--
-- This file is distributed under the terms in the attached LICENSE file.
-- If you do not find this file, copies can be found by writing to:
-- ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
--
-- Hakefile for lpuart
--
--------------------------------------------------------------------------
[
build library { target = "pl011",
cFiles = ["main.c"],
mackerelDevices = [ "pl011_uart" ],
architectures = ["armv8"]
}
]

132
usr/drivers/pl011/main.c Normal file
View File

@ -0,0 +1,132 @@
/**
* \file
* \brief Serial port driver.
*/
/*
* Copyright (c) 2020, ETH Zurich.
* Copyright (c) 2022, The University of British Columbia.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
* ETH Zurich D-INFK, CAB F.78, Universitaetstrasse 6, CH-8092 Zurich,
* Attn: Systems Group.
*/
#include <drivers/pl011.h>
#include <dev/pl011_uart_dev.h>
struct pl011_s {
struct event_closure int_handler;
struct pl011_uart_t dev;
};
static void hw_init(struct pl011_s *s)
{
pl011_uart_t *u = &s->dev;
/* Mask all interrupts: set all bits to zero. */
pl011_uart_IMSC_rawwr(u, 0);
/* Disable the UART before reconfiguring it. */
pl011_uart_CR_uarten_wrf(u, 0);
// Configure port to 38400 baud, 8 data, no parity, 1 stop (8-N-1)
//
// (This is a mild scam as system is running in QEMU)
//
// Note baud rate changes not committed in h/w until lcr_h
// written.
pl011_uart_IBRD_divint_wrf(u, 0xc); // Assuming UARTCLK is 7.3728MHz
pl011_uart_FBRD_divfrac_wrf(u, 0);
/* Configure the line control register. */
pl011_uart_LCR_H_t lcr = (pl011_uart_LCR_H_t)0;
/* Disable FIFOs. There's no way to get an interrupt when a single
* character arrives with FIFOs, so it's useless as a console. */
lcr = pl011_uart_LCR_H_fen_insert(lcr, 0);
/* Eight data bits. */
lcr = pl011_uart_LCR_H_wlen_insert(lcr, pl011_uart_bits8);
/* No parity. */
lcr = pl011_uart_LCR_H_pen_insert(lcr, 0);
/* One stop bit. */
lcr = pl011_uart_LCR_H_stp2_insert(lcr, 0);
pl011_uart_LCR_H_wr(u, lcr);
/* Configure the main control register. */
pl011_uart_CR_t cr = (pl011_uart_CR_t)0;
/* No flow control. */
cr = pl011_uart_CR_ctsen_insert(cr, 0);
cr = pl011_uart_CR_rtsen_insert(cr, 0);
/* Enable transmit and receive. */
cr = pl011_uart_CR_txe_insert(cr, 1);
cr = pl011_uart_CR_rxe_insert(cr, 1);
/* Enable UART. */
cr = pl011_uart_CR_uarten_insert(cr, 1);
pl011_uart_CR_wr(u, cr);
}
errval_t pl011_init(struct pl011_s **s_ret, void *base)
{
PL011_DEBUG("Driver init\n");
assert(s_ret != NULL);
assert(base != NULL);
struct pl011_s *s = calloc(1, sizeof(struct pl011_s));
if (s == NULL) {
return LIB_ERR_MALLOC_FAIL;
}
*s_ret = s;
pl011_uart_initialize(&s->dev, base);
PL011_DEBUG("Initializing hw...");
hw_init(s);
return SYS_ERR_OK;
}
errval_t pl011_getchar(struct pl011_s *s, char *c)
{
pl011_uart_t *u = &s->dev;
assert(u->base != 0);
/* Acknowledge any interrupt. */
pl011_uart_ICR_rxic_wrf(u, 1);
/* check if there is data */
if (pl011_uart_FR_rxfe_rdf(u) == 1) {
return LPUART_ERR_NO_DATA;
}
/* store the return character */
*c = (char)pl011_uart_DR_data_rdf(u);
return SYS_ERR_OK;
}
errval_t pl011_enable_interrupt(struct pl011_s *s)
{
pl011_uart_t *u = &s->dev;
assert(u->base != 0);
// Receive interrupt enable
pl011_uart_ICR_rxic_wrf(u, 1);
pl011_uart_IMSC_rxim_wrf(u, 1);
return SYS_ERR_OK;
}
errval_t pl011_putchar(struct pl011_s *s, char c)
{
pl011_uart_t *u = &s->dev;
assert(u->base != 0);
while (pl011_uart_FR_txff_rdf(u) == 1)
;
pl011_uart_DR_rawwr(u, c);
return SYS_ERR_OK;
}

View File

@ -31,6 +31,7 @@
struct bootinfo *bi;
coreid_t my_core_id;
struct platform_info platform_info;
@ -59,6 +60,7 @@ bsp_main(int argc, char *argv[]) {
// Grading
grading_test_early();
// TODO: Spawn system processes, boot second core etc. here
// Grading
@ -88,23 +90,45 @@ app_main(int argc, char *argv[]) {
return LIB_ERR_NOT_IMPLEMENTED;
}
int main(int argc, char *argv[])
{
errval_t err;
/* obtain the core information from the kernel*/
err = invoke_kernel_get_core_id(cap_kernel, &my_core_id);
if (err_is_fail(err)) {
USER_PANIC_ERR(err, "failed to obtain the core id from the kernel\n");
}
/* Set the core id in the disp_priv struct */
err = invoke_kernel_get_core_id(cap_kernel, &my_core_id);
assert(err_is_ok(err));
disp_set_core_id(my_core_id);
debug_printf("init: on core %" PRIuCOREID ", invoked as:", my_core_id);
/* obtain the platform information */
err = invoke_kernel_get_platform_info(cap_kernel, &platform_info);
if (err_is_fail(err)) {
USER_PANIC_ERR(err, "failed to obtain the platform info from the kernel\n");
}
char *platform;
switch (platform_info.platform) {
case PI_PLATFORM_QEMU:
platform = "QEMU";
break;
case PI_PLATFORM_IMX8X:
platform = "IMX8X";
break;
default:
platform = "UNKNOWN";
}
debug_printf("init domain starting on core %" PRIuCOREID " (%s), invoked as:", my_core_id, platform);
for (int i = 0; i < argc; i++) {
printf(" %s", argv[i]);
}
printf("\n");
fflush(stdout);