diff --git a/doc/lab-01_02.typ b/doc/lab-01_02.typ index 67d226a..d0153d2 100644 --- a/doc/lab-01_02.typ +++ b/doc/lab-01_02.typ @@ -331,14 +331,20 @@ for (int i = 0; i < elements; i++) { "temperature" = -1991 dot "register value" / 10 + 223000 $ - The chip ID can be verified in ```/proc/iomem```. - - The register value of the temperature can be verified in the file: ```/sys/class/thermal/thermal_zone0/temp```. - + The chip ID can be verified in ```/proc/iomem```. + The register value of the temperature can be verified in the file: ```/sys/class/thermal/thermal_zone0/temp```. The MAC address can be verified with ``` ifconfig```. ] ) +The resources are savec in a struct: +```bash +static struct resource* resources[3] = {[0] = 0,}; +``` +resources[0] is reserved for the chip ID, resources[1] for the temperature sensor and resources[2] for the Ethernet controller. + + + //------------------- // Exercise 6: Kernel thread //------------------- diff --git a/src/01-skeleton/skeleton.c b/src/01-skeleton/skeleton.c index 55d29ed..cdab855 100644 --- a/src/01-skeleton/skeleton.c +++ b/src/01-skeleton/skeleton.c @@ -5,37 +5,51 @@ #include // needed for module parameters -#include -#include +#include // dynamic memory allocation +#include // linked list #include +#include +#include + + #define TEXT_LENGTH_MAX 255 + static char* text = "dummy text"; module_param(text, charp, 0664); static int elements = 1; module_param(elements, int, 0); + +// Ex04 - Dynamic memory allocation and linked list struct element { char text[TEXT_LENGTH_MAX]; - int unique_number; + int32_t unique_number; struct list_head node; }; static LIST_HEAD (list_unique_elements); + +// Ex05 - Memory-mapped I/O +static struct resource* resources[3] = {[0] = 0,}; + + static int __init skeleton_init(void) { - pr_info("Linux module skeleton ex04 loaded\n"); + pr_info("Linux module skeleton ex05 loaded\n"); pr_debug(" text: %s\n elements: %d\n", text, elements); + + // Ex04 - Dynamic memory allocation and linked list struct element* element_ptr = kcalloc(elements, sizeof(struct element), GFP_KERNEL); if (element_ptr == 0) { pr_err("Failed to allocate memory for %d elements\n", elements); return -ENOMEM; } - int i; - const int length = TEXT_LENGTH_MAX - 1; + uint8_t i; + const uint8_t length = TEXT_LENGTH_MAX - 1; for (i = 0; i < elements; i++) { struct element* e = element_ptr + i; if (e != 0) { @@ -45,10 +59,75 @@ static int __init skeleton_init(void) { pr_info ("add element %d: %s\n", e->unique_number, e->text); } } + + // Ex05 - Memory-mapped I/O + unsigned char* registers[3] = {[0] = 0,}; + uint32_t chipid[4] = {[0] = 0,}; + uint32_t temperature = 0; + uint32_t mac_address[2] = {[0] = 0,}; + + resources[0] = request_mem_region(0x01c14000, 0x1000, "nanopi - chip ID"); + resources[1] = request_mem_region(0x01C25000, 0x1000, "nanopi - temperature sensor"); + resources[2] = request_mem_region(0x01C30000, 0x1000, "nanopi - Ethernet controller"); + if ((resources[0] == 0) || (resources[1] == 0) || (resources[2] == 0)) { + pr_err("Failed to reserve memory region for chip ID, temperature sensor or Ethernet controller\n"); + return -EFAULT; + } + + registers[0] = ioremap(0x01c14000, 0x1000); + registers[1] = ioremap(0x01C25000, 0x1000); + registers[2] = ioremap(0x01C30000, 0x1000); + if (registers[0] == 0) { + pr_err("Failed to map processor registers for chip ID\n"); + return -EFAULT; + } + if (registers[1] == 0) { + pr_err("Failed to map processor registers for temperature sensor\n"); + return -EFAULT; + } + if (registers[2] == 0) { + pr_err("Failed to map processor registers for Ethernet controller\n"); + return -EFAULT; + } + + chipid[0] = ioread32(registers[0] + 0x200); + chipid[1] = ioread32(registers[0] + 0x204); + chipid[2] = ioread32(registers[0] + 0x208); + chipid[3] = ioread32(registers[0] + 0x20c); + pr_info( + "chipid=%08x'%08x'%08x'%08x\n", + chipid[0], chipid[1], chipid[2], chipid[3] + ); + + temperature = -1991 * (int32_t) ioread32(registers[1] + 0x80) / 10 + 223000; + pr_info( + "temperature=%d (register value: %d)\n", + temperature, ioread32(registers[1] + 0x80) + ); + + mac_address[0] = ioread32(registers[2] + 0x50); + mac_address[1] = ioread32(registers[2] + 0x54); + pr_info( + "mac-addr=%02x:%02x:%02x:%02x:%02x:%02x\n", + (mac_address[1] >> 0) & 0xff, + (mac_address[1] >> 8) & 0xff, + (mac_address[1] >> 16) & 0xff, + (mac_address[1] >> 24) & 0xff, + (mac_address[0] >> 0) & 0xff, + (mac_address[0] >> 8) & 0xff + ); + + iounmap(registers[0]); + iounmap(registers[1]); + iounmap(registers[2]); + + return 0; } static void __exit skeleton_exit(void) { + + // Ex04 - Dynamic memory allocation and linked list struct element* e; while (!list_empty(&list_unique_elements)) { @@ -57,6 +136,12 @@ static void __exit skeleton_exit(void) { list_del(&e->node); kfree(e); } + + // Ex05 - Memory-mapped I/O + if (resources[0] != 0) release_mem_region(0x01c14000, 0x1000); + if (resources[1] != 0) release_mem_region(0x01C25000, 0x1000); + if (resources[2] != 0) release_mem_region(0x01C30000, 0x1000); + pr_info ("Linux module skeleton unloaded\n"); }