Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++

Linux with MMU on NEEK

Altera_Forum
Honored Contributor II
2,937 Views

Hi, all. 

 

I'm testing Linux MMU version, on my NEEK. 

 

http://www.nioswiki.com/linux 

 

It works fine and I can use "bash" shell. This is the evident proof that we are using the true 'fork' instead of 'vfork'. 

 

May be this will depends on the version, but TSE driver claims an error and doesn't work on this design. The error is 

 

ERROR: altera_tse.c:1666: request_mem_region() failed I think that this error is caused by misunderstanding of the usage for the function request_mem_region(). Inside of the request_mem_region(), the function __request_region() is called. If the resource has been already registered, this function returns a non-NULL value, that is the pointer for its resource. But the resource 'sgdma_rx_base' is already registered in the initialization process, so this function returns the 'conflict' and  

 

if (!request_mem_region(sgdma_rx_base, sgdma_rx_size, "altera_tse")) { is always true. So I made a dirty patch, 

 

if (!request_mem_region(sgdma_rx_base, sgdma_rx_size, "altera_tse")) { reg_resource = __request_region(&iomem_resource, sgdma_rx_base, sgdma_rx_size, "altera_tse", 0); if (reg_resource != NULL && reg_resource->flags & IORESOURCE_BUSY) { printk(KERN_ERR "ERROR: %s:%d: request_mem_region() failed\n", __FILE__, __LINE__); ret = -EBUSY; goto out_sgdma_rx; } } Moreover, the author is forgetting that the DMA is working in the physical address world, 

so we need to set the pointers of descripters like 

// desc->source = read_addr; desc->source = virt_to_phys(read_addr); // desc->destination = write_addr; desc->destination = virt_to_phys(write_addr); // desc->next = (unsigned int *)next; desc->next = (unsigned int *)((unsigned long)next & 0x1fffffffUL); and so on. 

 

Also the frame buffer fb0 will not work well, because the driver 'altfb.c' is not implemented for Linux with MMU version. So I put some codes for altfb_mmap(), like 

/* We implement our own mmap to set MAY_SHARE and add the correct size */ static int altfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { unsigned long phys_addr, phys_size; unsigned long addr; unsigned long size = vma->vm_end - vma->vm_start; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; // vma->vm_flags |= VM_MAYSHARE | VM_SHARED; // vma->vm_start = info->screen_base; // vma->vm_end = vma->vm_start + info->fix.smem_len; /* check range */ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; if (offset + size > altfb_fix.smem_len) return -EINVAL; vma->vm_flags |= VM_IO | VM_RESERVED; addr = vma->vm_start; phys_addr = altfb_fix.smem_start + offset; if ((offset + size) < altfb_fix.smem_len) phys_size = size; else phys_size = altfb_fix.smem_len - offset; vma->vm_page_prot = __pgprot(_PAGE_PRESENT|_PAGE_READ|_PAGE_WRITE); if (remap_pfn_range(vma, addr, phys_addr >> PAGE_SHIFT, phys_size, vma->vm_page_prot)) return -EAGAIN; return 0; } and rewrite the DMA descripters like 

desc->next = (void *)virt_to_phys((desc + 1)); So now, I can evoke telnetd and control NEEK through ethernet, and use Nano-X on Linux MMU version, but can't enter ftp session, because 'getservbyname()' function will not work well.  

I don't know the directory that the souce of 'getservbyname()' is included. Would anyone please tell me where is it? 

 

Thank you, in advance.
0 Kudos
95 Replies
Altera_Forum
Honored Contributor II
802 Views

Thank you very much. Your feedback is very helpful. 

 

The getservbyname is of glibc nss/inet. 

Please follow this file to get the toolchain source, 

http://sopc.et.ntust.edu.tw/pub/gnutools/nios2gcc4/readme 

 

- Hippo
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Maybe lib nss is missing, 

Please try turn off trim libs with, 

 

Blackfin build options --> Cull unused ELF shared libraries --> no 

 

- Hippo
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Hi, 

 

Thank you, Hippo. By selecting 'Blackfin build options --> Cull unused ELF shared libraries --> no', I was able to add the libraries 'libnss***.so' to /lib. Now 'inetd' and 'ftpd' are working well. But it seems that 'getenv()' that is used in 'ts_calibrate', will not work well yet. 

I haven't found the cause out and understood whether this is generated by libraries or not. 

 

I have another question. In 'nios2-linux/linux-2.6/arch/nios2/mm/dma-noncoherent.c', the function 'dma_alloc_coherent()' uses a macro 'UNCAC_ADDR()'. This macro transfers the input address like 

 

# define UNCAC_ADDR(addr) ((addr) - PAGE_OFFSET + UNCAC_BASE) but, UNCAC_BASE is set  

# define UNCAC_BASE 0xa0000000 in 'spaces.h'. Why? This memory space has a special meaning?
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

I think the uncached mapping was strange. 

I am reworking the UNCAC_ADDR in page.h, like, 

# define UNCAC_ADDR(addr) ((void *)((unsigned)(addr) | IO_REGION_BASE))# define CAC_ADDR(addr) ((void *)((unsigned)(addr) & ~IO_REGION_BASE | KERNEL_REGION_BASE)) 

 

Please also change the mmap in uClinux-dist/lib/tslib-1.0/tests/fbutils.c to shared_map. I will commit this later. 

 

- Hippo
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Fixed altfb, it was a bug to use ioremap to map return of kzalloc for sgdma descriptor table. Please see the update in unstable-nios2mmu branch of linux-2.6.git of sopc server. 

 

- Hippo
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

tslib worked after increase the number of tty in static device_table.txt. 

 

Though getenv() is still a problem. 

 

- Hippo
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Hi. 

 

 

--- Quote Start ---  

 

Fixed altfb, it was a bug to use ioremap to map return of kzalloc for sgdma descriptor table. Please see the update in unstable-nios2mmu branch of linux-2.6.git of sopc server. 

--- Quote End ---  

Oh sorry, I forgot to commit on this. Clearly we don't need to remap 'desc1'. In my case, I only comment the code 

// desc1 = ioremap((unsigned long)desc1, ndesc_size); out, and do 'flush_cache_all()' before the return. I will do git and check your code later. 

 

 

--- Quote Start ---  

 

Though getenv() is still a problem. 

- Hippo 

--- Quote End ---  

 

 

I think that this is only the shell problem. In 'hush' or 'bash', we need to export shell variables, like 

/> TSLIB_CONSOLEDEVICE=none /> export TSLIB_CONSOLEDEVICE

 

Now I'm tackling 'fltk' demo programs. They request 'libstdc++.so**', so I copied it, but will not run and say 'Segment fault'.(Segment? in Nios ?:)). I want to make 'core dump', but the kernel will not output those. Of course, I set 'ulimit -c unlimited'. Why? 

 

Thank you, in advance.
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Hi. 

 

 

--- Quote Start ---  

 

I want to make 'core dump', but the kernel will not output those. Of course, I set 'ulimit -c unlimited'. 

 

--- Quote End ---  

This was only the kernel configuration problem. In the 'menuconfig', 

 

[* ] Customize Kernel Settings (NEW)-> Exit->Exit-> General setup --->  

[*] Enable ELF core dumps 

 

so, we can get the 'core dump' with 'ulimit -c unlimited'.  

By setting 

echo 1 > /proc/sys/kernel/print-fatal-signals cat /proc/sys/kernel/print-fatal-signals 1we can get simple register's information. 

 

About 'fltk' demo program's 'Segmentation fault', it seems some bugs of libraries.:mad: 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

I tried hello,clock,editor of fltk. They all got "SEGV". I noticed that the fltk libs were built static. I wondered if we should try to build them shared. 

 

- Hippo
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Hi, 

 

 

--- Quote Start ---  

 

I tried hello,clock,editor of fltk. They all got "SEGV". I noticed that the fltk libs were built static. I wondered if we should try to build them shared. 

 

--- Quote End ---  

 

 

:confused: I think the 'editor' is using shared libraries. 

 

nios2-wrs-linux-gnu-g++ -Os -Wall -Wunused -Wno-format-y2k -fno-exceptions -fno-strict-aliasing -L/home/kazuyasu/nios2-linux/uClinux-dist/user/microwin/nxlib/fltk-1.1.8rc3/../nxlib-0.45 -mhw-mul -mno-hw-mulx editor.o -o editor ../lib/libfltk_images.a ../lib/libfltk.a -L../lib -lfltk_png -lz -lfltk_jpeg -ldl -lm Would you please try next command in your NEEK? 

 

/lib/ld.so.1 --list ./editor Now, I'm trying to debug the dynamic linking process by using GDB. 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Yes, it is shared. 

 

root:/> /lib/ld.so.1 --list /usr/bin/editor 

libz.so.1 => /lib/libz.so.1 (0x2aac8000) 

libdl.so.2 => /lib/libdl.so.2 (0x2aada000) 

libX11.so.6 => /usr/lib/libX11.so.6 (0x2aade000) 

libstdc++.so.6 => /lib/libstdc++.so.6 (0x2ab09000) 

libm.so.6 => /lib/libm.so.6 (0x2ac08000) 

libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x2acd1000) 

libc.so.6 => /lib/libc.so.6 (0x2ace1000) 

/lib/ld.so.1 (0x2aaa6000) 

 

- Hippo
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Hi. 

 

About 'fltk' demo programs, the 'Segmentation fault' is caused by a wrong linking process. All 'fltk' demo programs use the library 'libX11.so.6' and this library uses the nano-X library. But the nano-X library is generated as a static library i.e. 'libnano-X.a' in default configrations. This 'libnano-X.a' uses 'libc' and 'libc' is a shared library. So the generated code for the function 'GrSetErrorHandler' in libX11.so.6 is as follows. 

 

00017328 <GrSetErrorHandler>: 17328: defffc04 addi sp,sp,-16 1732c: dc400015 stw r17,0(sp) 17330: 044000f4 movhi r17,3 17334: 8c63be04 addi r17,r17,-28936 17338: dd400215 stw r21,8(sp) 1733c: 202b883a mov r21,r4 17340: 8809883a mov r4,r17 17344: dfc00315 stw ra,12(sp) 17348: dcc00115 stw r19,4(sp) 1734c: 0008ac40 call 8ac4 <_init+0x408> <----- 17350: d4e29517 ldw r19,-30124(gp) 17354: 8809883a mov r4,r17 17358: d5629515 stw r21,-30124(gp) 1735c: 00087a00 call 87a0 <_init+0xe4> <----- 17360: 9805883a mov r2,r19 17364: dfc00317 ldw ra,12(sp) 17368: dd400217 ldw r21,8(sp) 1736c: dcc00117 ldw r19,4(sp) 17370: dc400017 ldw r17,0(sp) 17374: dec00404 addi sp,sp,16 17378: f800283a ret When we execute this, the real code is as follows. 

 

0x2aae3328: addi sp,sp,-16 0x2aae332c: stw r17,0(sp) 0x2aae3330: movhi r17,3 0x2aae3334: addi r17,r17,-28936 0x2aae3338: stw r21,8(sp) 0x2aae333c: mov r21,r4 0x2aae3340: mov r4,r17 0x2aae3344: stw ra,12(sp) 0x2aae3348: stw r19,4(sp) 0x2aae334c: call 0x20008ac4 <----- 0x2aae3350: ldw r19,-30124(gp) 0x2aae3354: mov r4,r17 0x2aae3358: stw r21,-30124(gp) 0x2aae335c: call 0x200087a0 <----- 0x2aae3360: mov r2,r19 0x2aae3364: ldw ra,12(sp) 0x2aae3368: ldw r21,8(sp) 0x2aae336c: ldw r19,4(sp) 0x2aae3370: ldw r17,0(sp) 0x2aae3374: addi sp,sp,16 0x2aae3378: ret Of cource these relocations are wrong and the calling address '0x20008ac4' etc. will make 'Segmentation faults' . 

 

The easy way to avoid this failure is to make the nano-X library as a shared library. Inside the config file '/home/**/nios2-linux/uClinux-dist/user/microwin/src/config', change 

 

# #################################################################### # Libraries to build: microwin, nano-X, nanowidget, object frameworks# # ################################################################### MICROWIN = Y NANOX = Y SHAREDLIBS = Y <---- Change this from N to Y OBJFRAMEWORK = N flush the contents of the directory ' /home/**/nios2-linux/uClinux-dist/user/microwin/src/lib' and libX11.so.6.2 in '/home/**/nios2-linux/uClinux-dist/user/microwin/nxlib/nxlib-0.45', we can get new 'libX11.so.6.2' by 'make'. After copying the new library with 'libnano-X.so' and 'libstdc++.so.6', we can evoke 'hello', 'clock' and 'editor' successfully. But 'valuator' will generate SEGV, when I touch its dials. Why? 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Hi. 

 

I ported a SD-SPI IP to my NEEK according to the instruction 

 

http://www.alteraforum.com/forum/showthread.php?t=18875

 

The boot messages are 

mmc_spi spi2.0: ASSUMING SPI bus stays unshared! mmc_spi spi2.0: ASSUMING 3.2-3.4 V slot power mmc_spi spi2.0: SD/MMC host mmc0, no DMA, no WP, no poweroff TCP cubic registered NET: Registered protocol family 17 RPC: Registered udp transport module. RPC: Registered tcp transport module. mmc0: host does not support reading read-only switch. assuming write-enable. mmc0: new SD card on SPI mmcblk0: mmc0:0000 SD01G 968 MiB mmcblk0:

 

So I hit the command 'mount -t vfat /dev/mmcblk0 /mnt', but it claims 'No such device or address'. I wondered and searched the cause in the kernel carefully, but could'nt find the bug. It clearly initializes the SD driver and reads informations... Finally I saw the Manpage of 'mount(2)' and knew the exact meaning of 'ENXIO'. It saies that 'The major number of the block device source is out of range'.  

In the file '/home/***/nios2-linux/uClinux-dist/vendors/Altera/nios2/device_table.txt' 

# mmc block devices /dev/mmc0 b 640 0 0 197 0 0 1 - /dev/mmcblk0 b 640 0 0 197 0 0 1 - /dev/mmcblk0p1 b 640 0 0 197 1 0 1 - /dev/mmcblk0p2 b 640 0 0 197 2 0 1 - /dev/mmcblk0p3 b 640 0 0 197 3 0 1 - Of cource, the true major number of 'mmc' is 179... Hey, Give me a break! 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Yes, it was a typo. It was fixed a while ago. Please pull or rebase from the trunk branch of uClinux-dist.git of sopc or blackfin's. I also added the "SHAREDLIBS" Kconfig for microwin. Thanks. 

 

- Hippo
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Hi, 

 

Thank you, Hippo. And now, I'm trying to use swap file. First of all, Wind River didn't implement swap function. Moreover they didn't use 'vmalloc' at all. This means that they left us the last wonderland of Nios MMU (Bugs:D). 

Unfortunately, swapon system call uses 'vmalloc', we must repair its bug. 

In the file '/home/***/nios2-linux/linux-2.6/arch/nios2/mm/fault.c', the codes 

vmalloc_fault: { /* * Synchronize this task's top level page-table * with the 'reference' page table. * * Do _not_ use "tsk" here. We might be inside * an interrupt in the middle of a task switch.. */# define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))# define __pgd_offset(address) pgd_index(address) int offset = __pgd_offset(address); pgd_t *pgd, *pgd_k; pud_t *pud, *pud_k; pmd_t *pmd, *pmd_k; pte_t *pte_k; # if 1 /* FIXME: Is this entierly correct ? */ pgd = (pgd_t *) pgd_current + offset;# else pgd = &current->mm->pgd;# endif pgd_k = init_mm.pgd + offset; if (!pgd_present(*pgd_k)) goto no_context; set_pgd(pgd, *pgd_k); pud = pud_offset(pgd, address); pud_k = pud_offset(pgd_k, address); if (!pud_present(*pud_k)) goto no_context; pmd = pmd_offset(pud, address); pmd_k = pmd_offset(pud_k, address); if (!pmd_present(*pmd_k)) goto no_context; set_pmd(pmd, *pmd_k); pte_k = pte_offset_kernel(pmd_k, address); if (!pte_present(*pte_k)) { goto no_context; } flush_tlb_one(address); // <-- Add this to flush the contents of TLB. return; }copies (shares) the page tables, but they forgot to flush the old contents of TLB. Without this, Nios CPU will use the old contents of TLB (that generates the page fault) forever, and the kernel will freeze. 

About the swap functionality, we must implement next functions in the file '/home/***/nios2-linux/linux-2.6/arch/nios2/mm/pgtable.c'. 

/* Swap not implemented */ swp_entry_t __pte_to_swp_entry(pte_t pte){BUG();} pte_t __swp_entry_to_pte(swp_entry_t swp){BUG();} unsigned long __swp_type(swp_entry_t swp){BUG();} pgoff_t __swp_offset(swp_entry_t swp){BUG();} swp_entry_t __swp_entry(unsigned long type, pgoff_t offset){BUG();} To swap a page, the kernel must remember where the page is stored. But it isn't reasonable to request a new memory region in the case of memory shortage, Linux reuses the page table entry to remember two parameters. The parameter 'type' is used to distinguish the swap files, and the 'offset' is used to indicate the page location (offset) from the head of swap file. The function '__swp_entry' makes a new content of page entry for the page that will be swapped out. Of course, this fake page entry is loaded to the Nios TLB, and must generate page fault. To do this, normal CPU's MMU has a present bit, but the MMU of Nios is a little bit strange. 

 

tlbacc Control Register Fields 

|31 .....25 |24|23|22|21|20| 19 ..... 0| 

| ....IG..... |C | R|W| X |G |... PFN.. | 

 

To generate page faults, we must reset R = W = X = 0. Other bits IG are used as follows (these bits will not generate hardware page faults). 

/* TLBACC also has 7 IGNORE bits to use for SW defined attributes */# define _PAGE_PRESENT (1<<5)# define _PAGE_ACCESSED (1<<6) # define _PAGE_MODIFIED (1<<7) # define _PAGE_FILE (1<<8) # define _PAGE_VALID (1<<9)# define _PAGE_OLD (1<<10) The bit '_PAGE_FILE' is used other purpose and to enter the function 'do_swap_page',  

static inline int handle_pte_fault(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pte_t *pte, pmd_t *pmd, int write_access) { pte_t entry; spinlock_t *ptl; entry = *pte; if (!pte_present(entry)) { if (pte_none(entry)) { if (vma->vm_ops) { if (likely(vma->vm_ops->fault)) return do_linear_fault(mm, vma, address, pte, pmd, write_access, entry); } return do_anonymous_page(mm, vma, address, pte, pmd, write_access); } if (pte_file(entry)) return do_nonlinear_fault(mm, vma, address, pte, pmd, write_access, entry); return do_swap_page(mm, vma, address, pte, pmd, write_access, entry); } we must reset _PAGE_PRESENT and _PAGE_FILE bits, but set at least one bit because the function 'pte_none' checks those bits like 

/* FIXME: Today unmapped pages are mapped to the low physical addresses * and not 0 (to avoid to trigger the false alias detection in the iss) * Also check pte_clear. */ int pte_none(pte_t pte){# if 0 return (!((pte_val(pte) >> 20) & ~_PAGE_GLOBAL));# else return (!((pte_val(pte) >> 20) & ~(_PAGE_GLOBAL|0xf)));# endif }

So I designed the functions like 

swp_entry_t __pte_to_swp_entry(pte_t pte){return (swp_entry_t) {pte_val(pte)};} pte_t __swp_entry_to_pte(swp_entry_t swp){return (pte_t){swp.val};} unsigned long __swp_type(swp_entry_t swp){return ((swp.val >> 26) & 0x3);} pgoff_t __swp_offset(swp_entry_t swp){return (swp.val & 0xfffff);} swp_entry_t __swp_entry(unsigned long type, pgoff_t offset){return (swp_entry_t){(_PAGE_VALID << 20) | ((type & 0x3) << 26) | (offset & 0xfffff)};}

This limits the amount of swap files to 4, but I think it is enough:D. 

 

After the configuration 

Kernel/Library/Defaults Selection --->  

[*] Customize Kernel Settings (exit) (exit) 

General setup ---> 

[*] Support for paging of anonymous memory (swap)  

 

Kernel/Library/Defaults Selection --->  

[*] Customize Application/Library Settings (exit) (exit) 

BusyBox ---> Linux System Utilities --->  

[*] swaponoff 

, you can use swap files e.g. by the command 

 

>swapon /dev/*** 

 

. Of course you must prepare some storage. 

 

I gave some stress tests to my NEEK, and it works well. Next is a snapshot of '/proc/meminfo'. 

MemTotal: 26076 kB MemFree: 5080 kB Buffers: 0 kB Cached: 11980 kB SwapCached: 88 kB Active: 2260 kB Inactive: 2260 kB Active(anon): 2260 kB Inactive(anon): 2260 kB Active(file): 0 kB Inactive(file): 0 kB Unevictable: 11980 kB Mlocked: 0 kB SwapTotal: 351992 kB SwapFree: 351648 kB Dirty: 0 kB Writeback: 0 kB AnonPages: 4520 kB Mapped: 2036 kB Slab: 1716 kB SReclaimable: 336 kB SUnreclaim: 1380 kB PageTables: 208 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 365028 kB Committed_AS: 8052 kB VmallocTotal: 1048575 kB VmallocUsed: 176 kB VmallocChunk: 1048399 kB But Nano-X sometimes invokes 'oom-killer'. Why? 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Where to go from here ? Will your work be includsed into the community distribution ?  

 

-Michael
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Hi, 

 

>Where to go from here ?  

 

Where to go ? From here ?..... Ummm..., That is the question!:) 

 

>Will your work be includsed into the community distribution ?  

 

I don't know. May be, Hippo will decide it. 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

Hi, 

 

Now , I'm testing the KGDB kernel debugger(to check the swap functions:D). 

To communicate between NEEK and PC, we need one more serial communication method. Fortunately, we have one RS232c on NEEK, let's use it. 

To use the normal Altera UART, we must use the same name for our IP's one that is described in the file '/home/***/nios2-linux/linux-2.6/arch/nios2/kernel/config.c' 

static struct altera_uart_platform_uart nios2_uart_platform = { # ifdef UART0_BASE { .mapbase = UART0_BASE, .irq = UART0_IRQ, .uartclk = UART0_FREQ, },# endif for example, UART0. 

 

And we must add two polling functions to '/home/***/nios2-linux/linux-2.6/drivers/serial/altuart.c',  

# ifdef CONFIG_CONSOLE_POLL /* * Console polling routines for writing and reading from the uart while * in an interrupt or debug context. */ static int altera_uart_poll_get_char(struct uart_port *port) { unsigned char ch; while (!(readl(port->membase + ALTERA_UART_STATUS_REG) & ALTERA_UART_STATUS_RRDY_MSK)) ; return ch = readl(port->membase + ALTERA_UART_RXDATA_REG); } static void altera_uart_poll_put_char(struct uart_port *port, unsigned char c) { struct altera_uart *pp = container_of(port, struct altera_uart, port); unsigned long flags; unsigned short org_imr; /* copy of Local IMR mirror */ /* * Anyway disable the interrupts */ spin_lock_irqsave(&port->lock, flags); org_imr = pp->imr; pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); while (!altera_uart_tx_empty(port)) ; /* * Send the character out. * If a LF, also do CR... */ writel(c, port->membase + ALTERA_UART_TXDATA_REG); if (c == 10) { while (!altera_uart_tx_empty(port)) ; writel(13, port->membase + ALTERA_UART_TXDATA_REG); } /* * Finally, wait for transmitter to become empty * and restore the IRQ if it had been set */ while (!altera_uart_tx_empty(port)) ; if (org_imr & ALTERA_UART_CONTROL_TRDY_MSK) { pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK; writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); } spin_unlock_irqrestore(&port->lock, flags); } # endif /* CONFIG_CONSOLE_POLL */ and modify the 'struct uart_ops altera_uart_ops' 

/* * Define the basic serial functions we support. */ static struct uart_ops altera_uart_ops = { .tx_empty = altera_uart_tx_empty, .get_mctrl = altera_uart_get_mctrl, .set_mctrl = altera_uart_set_mctrl, .start_tx = altera_uart_start_tx, .stop_tx = altera_uart_stop_tx, .stop_rx = altera_uart_stop_rx, .enable_ms = altera_uart_enable_ms, .break_ctl = altera_uart_break_ctl, .startup = altera_uart_startup, .shutdown = altera_uart_shutdown, .set_termios = altera_uart_set_termios, .type = altera_uart_type, .request_port = altera_uart_request_port, .release_port = altera_uart_release_port, .config_port = altera_uart_config_port, .verify_port = altera_uart_verify_port,# ifdef CONFIG_CONSOLE_POLL .poll_get_char = altera_uart_poll_get_char, // <-- Add this. .poll_put_char = altera_uart_poll_put_char, // <-- Add this.# endif }; because when the kernel enters the debug session, all interrupts are disenabled. 

 

And we use a driver for kgdb that is '/home/***/nios2-linux/linux-2.6/drivers/serial/kgdboc.c' to communicate with our PC. This driver uses one tty serial device and search it in the code, 

__setup("kgdboc=", kgdboc_option_setup); static int configure_kgdboc(void) { struct tty_driver *p; int tty_line = 0; int err; err = kgdboc_option_setup(config); if (err || !strlen(config) || isspace(config)) goto noconfig; err = -ENODEV; p = tty_find_polling_driver(config, &tty_line); if (!p) goto noconfig; kgdb_tty_driver = p; kgdb_tty_line = tty_line; err = kgdb_register_io_module(&kgdboc_io_ops); if (err) goto noconfig; configured = 1; return 0; noconfig: config = 0; configured = 0; return err; } , but ..... , Hey, don't add any drivers after kgdboc.o ! 

# # Makefile for the kernel serial device drivers.# ....... obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o# obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altjuart.o obj-$(CONFIG_SERIAL_ALTERA_UART) += altuart.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o By the magic of '__init' macro, the linking order determines the loading order of drivers. 

 

.. to be continued.
0 Kudos
Altera_Forum
Honored Contributor II
802 Views

After these repairs, we must make two files, i.e. kgdb.c and its header, and place those in the directories of Nios Arch (kernel & include/asm). The samples are as follows 

/* * NIOS2 KGDB support * * Copyright (C) 2009 Nios Community Wiki * * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. */# include <linux/kgdb.h># include <linux/kdebug.h># include <linux/irq.h># include <linux/io.h># include <asm/cacheflush.h> static int wait_for_remote_debugger; /* * Replace the instruction immediately after the current instruction * (i.e. next in the expected flow of control) with a trap instruction, * so that returning will cause only a single instruction to be executed. * Note that this model is slightly broken for instructions with delay * slots (e.g. BS, BSR, BRA etc), where both the branch and the * instruction in the delay slot will be executed. */ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) { gdb_regs = 0; gdb_regs = regs->r1; gdb_regs = regs->r2; gdb_regs = regs->r3; gdb_regs = regs->r4; gdb_regs = regs->r5; gdb_regs = regs->r6; gdb_regs = regs->r7; gdb_regs = regs->r8; gdb_regs = regs->r9; gdb_regs = regs->r10; gdb_regs = regs->r11; gdb_regs = regs->r12; gdb_regs = regs->r13; gdb_regs = regs->r14; gdb_regs = regs->r15; gdb_regs = regs->ra; gdb_regs = regs->fp; gdb_regs = regs->sp; gdb_regs = regs->gp; gdb_regs = regs->estatus; gdb_regs = regs->ea; gdb_regs = regs->ea; } void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) { regs->r1 = gdb_regs; regs->r2 = gdb_regs; regs->r3 = gdb_regs; regs->r4 = gdb_regs; regs->r5 = gdb_regs; regs->r6 = gdb_regs; regs->r7 = gdb_regs; regs->r8 = gdb_regs; regs->r9 = gdb_regs; regs->r10 = gdb_regs; regs->r11 = gdb_regs; regs->r12 = gdb_regs; regs->r13 = gdb_regs; regs->r14 = gdb_regs; regs->r15 = gdb_regs; regs->ra = gdb_regs; regs->fp = gdb_regs; regs->sp = gdb_regs; regs->gp = gdb_regs; regs->estatus = gdb_regs; regs->ea = gdb_regs; } void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) { gdb_regs = p->thread.kregs->sp; gdb_regs = p->thread.kregs->ea; } int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, char *remcomInBuffer, char *remcomOutBuffer, struct pt_regs *linux_regs) { unsigned long addr; char *ptr; int cpu = smp_processor_id(); switch (remcomInBuffer) { case 's': case 'c': /* handle the optional parameter */ ptr = &remcomInBuffer; if (kgdb_hex2long(&ptr, &addr)) linux_regs->ea = addr; case 'D': case 'k': atomic_set(&kgdb_cpu_doing_single_step, -1); if (remcomInBuffer == 's') atomic_set(&kgdb_cpu_doing_single_step, cpu); return 0; } /* this means that we do not want to exit from the handler: */ return -1; } /* KGDB Breakpoint handler */ asmlinkage void kgdb_breakpoint_c(struct pt_regs *fp) { /* The breakpoint entry code has moved the PC on by 4 bytes, so we must */ /* move it back. This could be done on the host but we do it here */ if (!wait_for_remote_debugger) fp->ea -= 4; else /* pass the first trap 0x1e code */ wait_for_remote_debugger = 0; //printk("KGDB Breakpoint detected, instr=0x%08lx ea=0x%08lx ra=0x%08lx sp=0x%08lx\n", *(unsigned long*)fp->ea, fp->ea, fp->ra, fp->sp); kgdb_handle_exception(30, SIGTRAP, 0, fp); //printk("GOOD LUCK!! instr=0x%08lx ea=0x%08lx\n", *(volatile unsigned long*)fp->ea, (volatile unsigned long*)fp->ea); } int kgdb_arch_init(void) { wait_for_remote_debugger = 1; return 0; } void kgdb_arch_exit(void) { } struct kgdb_arch arch_kgdb_ops = { /* Breakpoint instruction: trap# 0x1e */ .gdb_bpt_instr = { 0xba, 0x6f, 0x3b, 0x00 }, }; # ifndef __ASM_NIOS2_KGDB_H# define __ASM_NIOS2_KGDB_H # include <asm/cacheflush.h># include <asm/ptrace.h> enum regnames { GDB_R0, GDB_AT, GDB_R2, GDB_R3, GDB_R4, GDB_R5, GDB_R6, GDB_R7, GDB_R8, GDB_R9, GDB_R10, GDB_R11, GDB_R12, GDB_R13, GDB_R14, GDB_R15, GDB_R16, GDB_R17, GDB_R18, GDB_R19, GDB_R20, GDB_R21, GDB_R22, GDB_R23, GDB_ET, GDB_BT, GDB_GP, GDB_SP, GDB_FP, GDB_EA, GDB_BA, GDB_RA, GDB_PC, GDB_ST, GDB_EST, GDB_BST, GDB_IE, GDB_IP, GDB_CID, GDB_CT6, GDB_EX, GDB_PTE, GDB_TBA, GDB_TBM, GDB_CT11,GDB_BAD, GDB_CFG, }; # define NUMREGBYTES ((GDB_CFG + 1) * 4) static inline void arch_kgdb_breakpoint(void) { __asm__ __volatile__ (".word 0x003b6fba"); } /* State info */ extern char in_nmi; /* Debounce flag to prevent NMI reentry*/ # define BUFMAX 2048 # define CACHE_FLUSH_IS_SAFE 1# define BREAK_INSTR_SIZE 4 # endif /* __ASM_NIOS2_KGDB_H */ And I'm using the code 'trap 30' as software break point ones, we must add some codes to '/home/***/nios2-linux/linux-2.6/arch/nios2/kernel/entry.S' 

trap_table: .word handle_system_call // 0 .word instruction_trap // 1 .word instruction_trap // 2 .word instruction_trap // 3 .word instruction_trap // 4 .word instruction_trap // 5 .word instruction_trap // 6 .word instruction_trap // 7 .word instruction_trap // 8 .word instruction_trap // 9 .word instruction_trap // 10 .word instruction_trap // 11 .word instruction_trap // 12 .word instruction_trap // 13 .word instruction_trap // 14 .word instruction_trap // 15 .word instruction_trap // 16 .word instruction_trap // 17 .word instruction_trap // 18 .word instruction_trap // 19 .word instruction_trap // 20 .word instruction_trap // 21 .word instruction_trap // 22 .word instruction_trap // 23 .word instruction_trap // 24 .word instruction_trap // 25 .word instruction_trap // 26 .word instruction_trap // 27 .word instruction_trap // 28 .word instruction_trap // 29# ifdef CONFIG_KGDB .word handle_kgdb_breakpoint // 30 KGDB breakpoint# else .word instruction_trap // 30# endif .word handle_breakpoint // 31 and 

handle_diverror: call handle_illegal_c br ret_from_exception # ifdef CONFIG_KGDB handle_kgdb_breakpoint: call kgdb_breakpoint_c br ret_from_exception# endif /* * Beware - when entering resume, prev (the current task) is

 

And repair the Kconfig file '/home/***/nios2-linux/linux-2.6/lib/Kconfig.kgdb' as 

config HAVE_ARCH_KGDB bool menuconfig KGDB bool "KGDB: kernel debugging with remote gdb"# depends on HAVE_ARCH_KGDB depends on DEBUG_KERNEL && EXPERIMENTAL help If you say Y here, it will be possible to remotely debug the kernel using gdb. It is recommended but not required, that you also turn on the kernel config option CONFIG_FRAME_POINTER to aid in producing more reliable stack backtraces in the external debugger. Documentation of kernel debugger is available at http://kgdb.sourceforge.net as well as in DocBook form in Documentation/DocBook/. If unsure, say N. , you can select the item of 'kgdb' in the menuconfig. So select 

 

Kernel hacking ---> 

[*] Kernel debugging  

 

[*] Compile the kernel with debug info  

 

[*] KGDB: kernel debugging with remote gdb ---> <*> KGDB: use kgdb over the serial console  

(kgdboc=ttyS0, 115200 kgdbwait) Default kernel command string  

 

and make your kernel again. (There is nothing that I'd forgotten to write, maybe... Opps, don't forget to add 'obj-$(CONFIG_KGDB) += kgdb.o' to the Makefile '/home/***/nios2-linux/linux-2.6/arch/nios2/kernel/Makefile'.:p) 

After getting the kmsg 

 

KGDB: Waiting for remote debugger 

 

evoke 'gdb' by 'nios2-wrs-linux-gnu-gdb -b 115200' and we can connect the 'kgdb' to our PC with a command e.g. 'target remote /dev/ttyS*'. After the connection, by setting some breakpoints e.g.  

 

symbol-file vmlinux 

b load_elf_binary  

continue 

 

, we can make break at the first program loading. 

 

Happy Debugging ! (and I shoud debug kgdb.c with KGDB.:D) 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
724 Views

Awesome :)  

 

I do hope that this gets into the official distribution, so that we are able to use it just by setting the appropriate config option.  

 

Moreover it then would be great to have a Wiki page describing the ways possibilities and how to do this using Eclipse as a gdb frontend.  

 

(Do you know the book "The Art of Debugging with GDB, DDD, and Eclipse" ? ) 

 

-Michael
0 Kudos
Reply