Skip to content

Commit

Permalink
Added memory source
Browse files Browse the repository at this point in the history
  • Loading branch information
vgonisanz committed May 7, 2017
1 parent e67fadb commit d6b097a
Show file tree
Hide file tree
Showing 8 changed files with 326 additions and 5 deletions.
9 changes: 7 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,30 @@ set(CMAKE_EXE_LINKER_FLAGS "-T ${LINKER_SCRIPT}")
file(GLOB KLIBC_SRC "klibc/src/*.c")
set(BOOT_SRC "init/boot.s")
set(ENTRY_SRC "init/entry.S")
set(COMMON_SRC "common/device.c"
set(COMMON_SRC "common/device.c"
"common/panic.c")
set(GPIO_SRC "gpio/gpio.c")
set(LED_SRC "led/led.c")
set(UART_SRC "uart/uart.c")
set(VIDEO_SRC "video/framebuffer.c")
set(MEMORY_SRC "memory/memory.c"
"memory/mailbox.c")
set(IRQ_SRC "irq/irq.c")
set(EXCEPTIONS_SRC "exceptions/exceptions.c")
set(TIMER_SRC "timer/timer.c")
set(ATAGS_FILE "init/atags.c")
set(KERNEL_MAIN_FILE "init/kernel.c")

set(KERNEL_SOURCES
set(KERNEL_SOURCES
${BOOT_SRC}
${ENTRY_SRC}
${COMMON_SRC}
${GPIO_SRC}
${LED_SRC}
${KLIBC_SRC}
${UART_SRC}
${VIDEO_SRC}
${MEMORY_SRC}
${IRQ_SRC}
${EXCEPTIONS_SRC}
${TIMER_SRC}
Expand Down
4 changes: 2 additions & 2 deletions src/common/peripherals.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

#include <types.h>

// Raspberry pi peripherals base address
/* Physical addresses range from 0x20000000 to 0x20FFFFFF for Raspberry pi peripherals */
#define PERIPHERALS_BASE 0x20000000

inline void mmio_write(u32 reg, u32 data)
{
*(volatile u32 *)reg = data;
}

inline u32 mmio_read(u32 reg)
{
return *(volatile u32 *)reg;
Expand Down
6 changes: 5 additions & 1 deletion src/init/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <gpio/gpio.h>
#include <led/led.h>
#include <uart/uart.h>
#include <video/framebuffer.h>
#include <memory/memory.h>
#include <timer/timer.h>

#if defined(__cplusplus)
Expand Down Expand Up @@ -64,14 +66,16 @@ void kernel_main(u32 r0, u32 r1, u32 atags)
blink(3, 1000000);

device_init();

if ((uart_dev_id = uart_register()) < 0)
{
kernel_panic();
}

welcome_message();
resume_atags();
init_memory();
init_framebuffer();

u8 buffer;
while (true)
Expand Down
26 changes: 26 additions & 0 deletions src/memory/barrier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*** Memory barriers or data cache invalidation/flushing may be required around mailbox accesses ***/

#ifndef _MEM_BARRIER_H
#define _MEM_BARRIER_H

/* Invalidate Entire Data Cache */
#define invalidate_cache() asm volatile \
("mcr p15, #0, %[zero], c7, c6, #0" : : [zero] "r" (0) )

/* Clean Entire Data Cache */
#define clear_cache() asm volatile \
("mcr p15, #0, %[zero], c7, c10, #0" : : [zero] "r" (0) )

/* Clean and Invalidate Entire Data Cache */ /* TODO use before read mailbox and check if really needed */
#define flush_cache() asm volatile \
("mcr p15, #0, %[zero], c7, c14, #0" : : [zero] "r" (0) )

/* Data Synchronization Barrier: No instruction after the DSB can run until all instructions before it have */
#define data_sb() asm volatile \
("mcr p15, #0, %[zero], c7, c10, #4" : : [zero] "r" (0) )

/* Data Memory Barrier: No memory access after the DMB can run until all memory accesses before it have completed */
#define data_mb() asm volatile \
("mcr p15, #0, %[zero], c7, c10, #5" : : [zero] "r" (0) )

#endif /* _MEM_BARRIER_H */
78 changes: 78 additions & 0 deletions src/memory/mailbox.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include <memory/mailbox.h>

#include <memory/barrier.h>
#include <memory/memory.h>

static volatile mske_mailbox* const mailbox0 = (mske_mailbox*)MAILBOX0_ADDRESS;

unsigned int read_mailbox(unsigned int channel)
{
/* default data error */
unsigned int data = 0xffffffff;
unsigned int count = 0;

/* Check if channel is no greater than 4 bits */
if(channel > 15)
{
return data;
}

/* Repeat until match the channel number desired. If nothing recieved, it eventually give up and returns 0xffffffff */
while(1)
{
/* Read the status register until the empty flag is not set, wait for the mailbox to be available to read */
while (mailbox0->status & MAILBOX_EMPTY)
{
/* Need to check if this is the right thing to do */
flush_cache();

/* This is an arbitrary large number */
if(count++ >(1<<25))
{
return data;
}
}
/* Read data from the read register */
data_mb();
data = mailbox0->read;
data_mb();

/* Check if is the channel number desired */
if ((data & 0xF) == channel)
{
data >>= 4; /* TODO check if correct --> The upper 28 bits are the returned data */
return data;
}
}
}

int write_mailbox(unsigned int channel, unsigned int data)
{
/* default data error */
unsigned int result = -1;

/* Check if data override channel bits */
if(data & 0x0f)
{
return result;
}

/* Check if channel is no greater than 4 bits */
if(channel > 15)
{
return result;
}

/* Read the status register until the full flag is not set, wait for the mailbox to be available to write */
data_mb();
while( mailbox0->status & MAILBOX_FULL )
{
data_mb();
}

/* Write the data (shifted into the upper 28 bits) and channel (in the lower four bits) */
data_mb();
mailbox0->write = data | channel;
result = 0;
return result;
}
62 changes: 62 additions & 0 deletions src/memory/mailbox.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Mailbox:
* Each mailbox is an 8-deep FIFO of 32-bit words, which can be read (popped)/written (pushed) by the ARM and VideoCore and defines the following channels:
* 0: Power management
* 1: Framebuffer
* 2: Virtual UART
* 3: VCHIQ
* 4: LEDs
* 5: Buttons
* 6: Touch screen
* 7:
* 8: Property tags (ARM -> VideoCore)
* 9: Property tags (VideoCore -> ARM)
*
* Mailbox Peek Read/Write Status Sender Config
* 0 0x10 0x00 0x18 0x14 0x1c
* 1 0x30 0x20 0x38 0x34 0x3c
*
* All registers are unsigned int (32 bits) little-endian.
*
* More info: https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes
*
*/
#ifndef _MAILBOX_H
#define _MAILBOX_H

#include <common/peripherals.h>

/* Base address for the mailbox registers */
#define MAILBOX_ADDRESS_BASE 0xB880
#define MAILBOX0_ADDRESS (PERIPHERALS_BASE + MAILBOX_ADDRESS_BASE)

/* Mailbox full: Bit 31 is set in the status register if there is no space to write into the mailbox */
#define MAILBOX_FULL 0x80000000

/* Mailbox empty: Bit 30 is set in the status register if there is nothing to read from the mailbox */
#define MAILBOX_EMPTY 0x40000000

/* Define channels */
#define MAILBOX_CHANNEL_ARM2VC 8
#define MAILBOX_CHANNEL_VC2ARM 9

typedef struct
{
unsigned int read;
unsigned int unused1;
unsigned int unused2;
unsigned int unused3;
unsigned int poll;
unsigned int sender;
unsigned int status;
unsigned int configuration;
unsigned int write;
} mske_mailbox;

/* Read a channel. The channel must be zero to 15 */
extern unsigned int read_mailbox(unsigned int channel);

/* Write the given data to the channel. The channel must be zero to 15 and value in last 4 bits */
extern int write_mailbox(unsigned int channel, unsigned int data);

#endif /* _MAILBOX_H */
105 changes: 105 additions & 0 deletions src/memory/memory.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include <memory/memory.h>

#include <common/io.h>

#define MEMORY_SIZE 64
#define MEMORY_ALIGN 256


/* Translation table 0: First 64 MB in memory. Needs to be aligned to its size (i.e: 64*4 bytes) */
unsigned int pagetable0[MEMORY_SIZE] __attribute__ ((aligned (MEMORY_ALIGN)));

/* Need to access the page table, etc as physical memory */
static unsigned int *pagetable = (unsigned int * const) mem_p2v(0x4000); /* 16k */

void init_memory(void)
{
printk("Initializing memory...\n");

unsigned int x;
unsigned int pagetable0_address;

/* Translation table 0 - covers the first 64 MB, currently nothing mapped in it. */
for(x = 0; x < MEMORY_SIZE; x++)
{
pagetable0[x] = 0;
}
printk("Created pagetable with %d MBs.\n", MEMORY_SIZE);

/* Get physical address of pagetable 0 */
pagetable0_address = mem_v2p((unsigned int) &pagetable0);

/* Use translation table 0 up to 64MB */
asm volatile("mcr p15, 0, %[n], c2, c0, 2" : : [n] "r" (6));

/* Translation table 0 - ARM1176JZF-S manual, 3-57 */
asm volatile("mcr p15, 0, %[addr], c2, c0, 0" : : [addr] "r" (pagetable0_address));

/* Invalidate the translation lookaside buffer (TLB): ARM1176JZF-S manual, p. 3-86 */
asm volatile("mcr p15, 0, %[data], c8, c7, 0" : : [data] "r" (0));

printk("Memory initialized!\n");
}

unsigned int mem_v2p(unsigned int virtual_address)
{
unsigned int pagetable_data = pagetable[virtual_address >> 20];
unsigned int type_of_entry = pagetable_data & 3;

/* Translation fault */
if(type_of_entry == 0)
{
return 0xffffffff;
}

/* Coarse page table */
if(type_of_entry == 1)
{
unsigned int coarse_pagetable_data;
coarse_pagetable_data = ((unsigned int *)(VIRTUAL_ADDRESS_BASE + (pagetable_data & 0xfffffc00)))[(virtual_address >> 12) & 0xff];

/* Nothing mapped */
if((coarse_pagetable_data & 3) == 0)
{
return 0xffffffff;
}

/* Small (4k) page */
if(coarse_pagetable_data & 2)
{
return (coarse_pagetable_data & 0xfffff000) + (virtual_address & 0xfff);
}

/* Large 64k page */
return (coarse_pagetable_data & 0xffff0000) + (virtual_address & 0xffff);
}

/* Sections */
if(type_of_entry == 2)
{
unsigned int physical_address;

/* SuperSection base */
physical_address = pagetable_data & 0xfff00000;

if(pagetable_data & (1<<18))
{
/* 16MB Supersection */
physical_address += virtual_address & 0x00ffffff;
}
else
{
/* 1MB Section */
physical_address += virtual_address & 0x000fffff;
}
return physical_address;
}

/* Reserved */
if(type_of_entry == 3)
{
return 0xffffffff;
}
/* Unknown problem, cannot come here */
return 0xffffffff;
}
41 changes: 41 additions & 0 deletions src/memory/memory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* The ARM section of the RAM starts at 0x00000000 and the VideoCore section of the RAM is mapped in only if the system is configured to support a memory mapped display.
* The bus addresses for RAM are set up to map onto the uncached bus address range on the VideoCore starting at 0xC0000000.
*
* Bus:
* The bus addresses for peripherals are set up to map onto the peripheral bus address range starting at 0x7E000000.
*
* Physical addresses:
* Peripherals will range from 0x20000000 to 0x20FFFFFF. Use peripherals.h to manage.
*
* Virtual addresses: (Check arm-c-virtual-addresses figure or BCM2835 ARM peripherals)
* Virtual addresses in user mode (i.e. seen by processes running in ARM Linux) will range between 0x00000000 and 0xBFFFFFFF.
* Virtual addresses in kernel mode will range between 0xC0000000 and 0xEFFFFFFF.
*
* DMA: use Direct access memory. DMA allows certain hardware subsystems to access main system memory (RAM) independent of the central processing unit (CPU). It is needed to ...
*
* Memory addresses summary:
* User process memory | 0x00000000 - 0x7fffffff = 0 - 2GB
* Peripherals | 0x20000000 - 0x20ffffff
* Physical memory | 0x80000000 - 0xa0ffffff
* Kernel data | 0xc0000000 - 0xefffffff
* Kernel code | 0xf0000000 - 0xffffffff
*/
#ifndef _MEMORY_H
#define _MEMORY_H

/*** Memory management ***/

/* Virtual addresses range defined as 0x80000000 offset */
#define VIRTUAL_ADDRESS_BASE 0x80000000

/* Initialise memory: Set up first 64MB of RAM as unmapped pagetable */
extern void init_memory(void);

/* Convert a physical address to a virtual one */
#define mem_p2v(X) (X+VIRTUAL_ADDRESS_BASE)

/* Convert a virtual address to a physical one by following the page table. Returns physical address, or 0xffffffff if the virtual address does not map - ARM1176-TZJS page 6-39 */
extern unsigned int mem_v2p(unsigned int virtual_address);

#endif /* _MEMORY_H */

0 comments on commit d6b097a

Please sign in to comment.