- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Maybe lib nss is missing,
Please try turn off trim libs with, Blackfin build options --> Cull unused ELF shared libraries --> no - Hippo- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
tslib worked after increase the number of tty in static device_table.txt.
Though getenv() is still a problem. - Hippo- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
1
we can get simple register's information. About 'fltk' demo program's 'Segmentation fault', it seems some bugs of libraries.:mad: Kazu
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi.
I ported a SD-SPI IP to my NEEK according to the instructionhttp://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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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 = ¤t->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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Where to go from here ? Will your work be includsed into the community distribution ?
-Michael- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page